/*
 * @(#) PMService.java 2013-7-22 下午2:24:34
 *
 * Copyright 2013 Rockwell Automation, Inc. All rights reserved.
 * Rockwell Automation PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
 */package com.osi.mes.pm;

import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
import java.util.Vector;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import pnuts.lang.Context;

import com.datasweep.compatibility.client.ATDefinition;
import com.datasweep.compatibility.client.ATHandler;
import com.datasweep.compatibility.client.ATRow;
import com.datasweep.compatibility.client.ATRowFilter;
import com.datasweep.compatibility.client.AlternateBomItem;
import com.datasweep.compatibility.client.BillOfMaterials;
import com.datasweep.compatibility.client.BomFilter;
import com.datasweep.compatibility.client.BomItem;
import com.datasweep.compatibility.client.Box;
import com.datasweep.compatibility.client.Carrier;
import com.datasweep.compatibility.client.CarrierFilter;
import com.datasweep.compatibility.client.Categorical;
import com.datasweep.compatibility.client.ConsumptionSet;
import com.datasweep.compatibility.client.DCInstance;
import com.datasweep.compatibility.client.DCInstanceFilter;
import com.datasweep.compatibility.client.DataCollectionItem;
import com.datasweep.compatibility.client.DataCollectionSet;
import com.datasweep.compatibility.client.DatasweepException;
import com.datasweep.compatibility.client.DeAnzaForm;
import com.datasweep.compatibility.client.DsMessages;
import com.datasweep.compatibility.client.FormFilter;
import com.datasweep.compatibility.client.Lot;
import com.datasweep.compatibility.client.LotFilter;
import com.datasweep.compatibility.client.LotHistory;
import com.datasweep.compatibility.client.MeasuredValue;
import com.datasweep.compatibility.client.Order;
import com.datasweep.compatibility.client.OrderFilter;
import com.datasweep.compatibility.client.OrderItem;
import com.datasweep.compatibility.client.OrderItemFilter;
import com.datasweep.compatibility.client.ParentATRow;
import com.datasweep.compatibility.client.Part;
import com.datasweep.compatibility.client.PartFilter;
import com.datasweep.compatibility.client.ProductionLine;
import com.datasweep.compatibility.client.Queue;
import com.datasweep.compatibility.client.Response;
import com.datasweep.compatibility.client.Route;
import com.datasweep.compatibility.client.RouteFilter;
import com.datasweep.compatibility.client.RuntimeDCS;
import com.datasweep.compatibility.client.Step;
import com.datasweep.compatibility.client.Subroutine;
import com.datasweep.compatibility.client.WorkCenter;
import com.datasweep.compatibility.manager.ServerImpl;
import com.datasweep.compatibility.pnuts.Functions;
import com.datasweep.compatibility.ui.CComponent;
import com.datasweep.compatibility.ui.CControl;
import com.datasweep.compatibility.ui.CheckBox;
import com.datasweep.compatibility.ui.FlatButton;
import com.datasweep.compatibility.ui.FlatLabel;
import com.datasweep.compatibility.ui.Form;
import com.datasweep.compatibility.ui.GroupBox;
import com.datasweep.compatibility.ui.MessageIdHolder;
import com.datasweep.compatibility.ui.MessagesHolder;
import com.datasweep.compatibility.ui.RadioButton;
import com.datasweep.compatibility.ui.TabPage;
import com.datasweep.compatibility.ui.Time;
import com.datasweep.compatibility.ui.grid.ColumnDefinition;
import com.datasweep.compatibility.ui.grid.DsGrid;
import com.datasweep.plantops.common.constants.ITrackedObjectConstants;
import com.datasweep.plantops.common.constants.filtering.IFilterComparisonOperators;
import com.datasweep.plantops.common.constants.filtering.IFilterSortOrders;
import com.datasweep.plantops.common.constants.filtering.IFormFilterAttributes;
import com.datasweep.plantops.common.constants.filtering.ILotFilterAttributes;
import com.datasweep.plantops.common.constants.filtering.IPartFilterAttributes;
import com.datasweep.plantops.common.constants.filtering.IWorkOrderFilterAttributes;
import com.datasweep.plantops.common.constants.filtering.IWorkOrderItemFilterAttributes;
import com.osi.mes.base.BaseService;
import com.osi.mes.base.object.UIData;
import com.osi.mes.constants.IATConstants;
import com.osi.mes.constants.IDCSCategory;
import com.osi.mes.constants.IDCSConstants;
import com.osi.mes.constants.IDateFormatConstants;
import com.osi.mes.constants.IOPCConstants;
import com.osi.mes.constants.ISystemDataConstants;
import com.osi.mes.constants.IUDADefinitions;
import com.osi.mes.pm.constants.IMaterialType;
import com.osi.mes.pm.constants.IMessageSign;
import com.osi.mes.pm.constants.IOrderState;
import com.osi.mes.pm.constants.IPMConstants;
import com.osi.mes.pm.object.AdditivePrescription;
import com.osi.mes.pm.object.ForeignMatter;
import com.osi.mes.pm.object.LotInfo;
import com.osi.mes.pm.object.MaterialSplitMethod;
import com.osi.mes.pm.object.WorkPlan;
import com.osi.mes.pm.object.UIOrder;
import com.osi.mes.pm.object.UIStep;
import com.osi.mes.pm.util.OrderTypeUtil;
import com.osi.mes.print.IPrintConstants;
import com.osi.mes.print.PrintComponent;
import com.rockwell.eventmanager.sheet.LiveDataEventContainer;
import com.rockwell.eventmanager.sheet.MessageGroupEventContainer;
import com.rockwell.ftpc.framework.common.DateTimeUtils;
import com.rockwell.ftpc.framework.common.ExcelData;
import com.rockwell.ftpc.framework.common.StringUtils;
import com.rockwell.ftpc.framework.common.XMLUtils;
import com.rockwell.ftpc.framework.common.XmlData;
import com.rockwell.ftpc.framework.exception.MESException;
import com.rockwell.livedata.GroupDataEvent;
import com.rockwell.livedata.ItemData;
import com.rockwell.livedata.LiveDataGroup;
import com.rockwell.livedata.LiveDataItem;
import com.rockwell.livedata.LiveDataItems;
import com.rockwell.livedata.LiveDataServer;
import com.rockwell.mes.rtmis.middle.utils.MDUtils;
import com.rockwell.transactiongrouping.UserTransaction;

public class PMService extends BaseService implements IPMConstants
{

	private static final String NULL = "";
	
	public PMService(Context context)
	{
		super(context);
	}
	
	public PMService(Functions functions)
	{
		super(functions);
	}
	
	/**
	 * 导入生产日计划
	 */
	public String importWorkPlan_(ExcelData excelData) throws MESException
	{
		try
		{
			int totalSize = excelData.getNumberOfRows();
			int creationNum = 0;
			int updateNum = 0;

			boolean isUpdate = false;
			if (totalSize > 0)
			{
				ATHandler atHandler = getFunctions().createATHandler(
					AT_TABLE_PM_WORK_PLAN);
				for (int i = 0; i < totalSize; i++)
				{
					
					try
					{
						String plannedDateStr = excelData.getValue(
							i, EXCEL_WORK_PLAN_PLANNED_DATE);
						String productionLineName = excelData.getValue(
							i, EXCEL_WORK_PLAN_PRODUCTION_LINE);
						String partDescription = excelData.getValue(
							i, EXCEL_WORK_PLAN_PART_DESCRIPTION);
						String partNumber = excelData.getValue(
							i, EXCEL_WORK_PLAN_SAP_CODE);
						String quantityStr = excelData.getValue(
							i, EXCEL_WORK_PLAN_PLANNED_QTY);
						String isTestStr = excelData.getValue(
							i, EXCEL_WORK_PLAN_IS_TEST);
						String comment = excelData.getValue(
							i, EXCEL_WORK_PLAN_COMMENT);

//						getFunctions().stringToTime(plannedDateStr, IDateFormatConstants.DATE_FORMAT_PLANNED_DATE);
//						Time plannedDate = DateTimeUtils.parseDateOfPnut(
//							plannedDateStr, IDateFormatConstants.DATE_FORMAT_PLANNED_DATE);
						Time plannedDate = new Time(plannedDateStr);
						Float plannedQty = Float.valueOf(quantityStr);
						Boolean isTest = StringUtils.isNull(isTestStr) ? false : WORK_PLAN_IS_TEST_TRUE
							.equals(isTestStr.trim());

						ATRow atRow = searchWorkPlans(
							plannedDate, partNumber, productionLineName);
						if (atRow != null)
						{
							isUpdate = true;
							Boolean isOrdered = atRow.getValue(IATConstants.AT_COLUMN_PM_WORK_PLAN_IS_ORDERED) == null?false:(Boolean)atRow.getValue(IATConstants.AT_COLUMN_PM_WORK_PLAN_IS_ORDERED);
							if(isOrdered)
							{
								continue;
							}
						}
						else
						{
							atRow = atHandler.createATRow();
							creationNum++;
							isUpdate = false;
						}

						atRow.setValue(
							AT_COLUMN_PM_WORK_PLAN_COMMENT, comment);
						atRow.setValue(
							AT_COLUMN_PM_WORK_PLAN_PLANNED_DATE, plannedDate);
						atRow.setValue(
							AT_COLUMN_PM_WORK_PLAN_PLANNED_QTY, plannedQty);
						atRow.setValue(
							AT_COLUMN_PM_WORK_PLAN_IS_TEST, isTest);
						atRow.setValue(
							AT_COLUMN_PM_WORK_PLAN_IMPORT_DATE, getTrxTime());
						atRow.setValue(
							AT_COLUMN_PM_WORK_PLAN_PRODUCTION_LINE, productionLineName);
						atRow.setValue(
							AT_COLUMN_PM_WORK_PLAN_PART_DESCRIPTION, partDescription);
						atRow.setValue(
							AT_COLUMN_PM_WORK_PLAN_SAP_CODE, partNumber);

						// 如果是更新
						if (isUpdate)
						{
							Response response = atRow.save(
								getTrxTime(), null, null);
							if (response.isOk())
							{
								updateNum++;
							}
						}
					}
					catch (Exception e)
					{
						if(!isUpdate)
						{
							creationNum--;
						}
					}
				}

				// 新建
				Response response = atHandler.save(
					getTrxTime(), null, null);
				if (response.isOk())
				{
//					return "共导入数据" + totalSize + "条，其中新建数据" + creationNum + "条，更新数据" + updateNum
//						+ "条，失败" + (totalSize - creationNum - updateNum) + "条";
					return getMessage("ERROR_1") + totalSize + getMessage("ERROR_2") + creationNum + getMessage("ERROR_3") + updateNum
						+ getMessage("ERROR_4") + (totalSize - creationNum - updateNum) + getMessage("ERROR_5");
				}
			}

//			return "导入数据数量为0";
			return getMessage("ERROR_6");
		}
		catch (Exception e)
		{
			throw new MESException(e, MODULE_PM, "导入生产日计划");
		}
	}
	
	/**
	 * 导入生产日计划
	 */
	public String importWorkPlan(ExcelData excelData) throws MESException
	{
		int totalSize = excelData.getNumberOfRows();
		int errorSize = 0;
		int updateSize = 0;
		int createSize = 0;
		ATDefinition atDefinition = getFunctions().getATDefinition(
			AT_TABLE_PM_WORK_PLAN);
		for (int i = 0; i < totalSize; i++)
		{
			try
			{
				String plannedDateStr = excelData.getValue(
					i, EXCEL_WORK_PLAN_PLANNED_DATE);
				String productionLineName = excelData.getValue(
					i, EXCEL_WORK_PLAN_PRODUCTION_LINE);
				String partDescription = excelData.getValue(
					i, EXCEL_WORK_PLAN_PART_DESCRIPTION);
				String partNumber = excelData.getValue(
					i, EXCEL_WORK_PLAN_SAP_CODE);
				String quantityStr = excelData.getValue(
					i, EXCEL_WORK_PLAN_PLANNED_QTY);
				String isTestStr = excelData.getValue(
					i, EXCEL_WORK_PLAN_IS_TEST);
				String comment = excelData.getValue(
					i, EXCEL_WORK_PLAN_COMMENT);
				
				validatePlannedDate(plannedDateStr);
				validateProductionLine(productionLineName);
				validateProduct(partNumber,partDescription);
				validateQty(quantityStr);
				validateIsTest(isTestStr);
				
				Boolean isTest = StringUtils.isNull(isTestStr) ? false : WORK_PLAN_IS_TEST_TRUE
					.equals(isTestStr.trim());
				
				Time plannedDate = new Time(plannedDateStr);
				Float plannedQty = Float.valueOf(quantityStr);
				
				ATRow atRow = searchWorkPlans(
					plannedDate, partNumber, productionLineName);
				if(atRow == null)
				{
					atRow = atDefinition.createATRow_();
					atRow.setValue(
						AT_COLUMN_PM_WORK_PLAN_COMMENT, comment);
					atRow.setValue(
						AT_COLUMN_PM_WORK_PLAN_PLANNED_DATE, plannedDate);
					atRow.setValue(
						AT_COLUMN_PM_WORK_PLAN_PLANNED_QTY, plannedQty);
					atRow.setValue(
						AT_COLUMN_PM_WORK_PLAN_IS_TEST, isTest);
					atRow.setValue(
						AT_COLUMN_PM_WORK_PLAN_IMPORT_DATE, getTrxTime());
					atRow.setValue(
						AT_COLUMN_PM_WORK_PLAN_PRODUCTION_LINE, productionLineName);
					atRow.setValue(
						AT_COLUMN_PM_WORK_PLAN_PART_DESCRIPTION, partDescription);
					atRow.setValue(
						AT_COLUMN_PM_WORK_PLAN_SAP_CODE, partNumber);
					Response response = atRow.save(null, null, null);
					if(response.isOk())
					{
						createSize++;
					}
					else
					{
						throwException(response.getFirstErrorMessage());
					}
				}
				else
				{
					//判断是否已经生成过工单
					Boolean isOrdered = atRow.getValue(IATConstants.AT_COLUMN_PM_WORK_PLAN_IS_ORDERED) == null?false:(Boolean)atRow.getValue(IATConstants.AT_COLUMN_PM_WORK_PLAN_IS_ORDERED);
					if(isOrdered)
					{
						// 若生成过工单，则判断是否已经发布
						String orderNumber = (String) atRow
							.getValue(IATConstants.AT_COLUMN_PM_WORK_PLAN_ORDER_NUMBER);
						UIOrder uiOrder = getUIOrder(orderNumber);
						String orderState = uiOrder.getOrderState();
						// 若已经发布
						if (!IOrderState.CREATED.equals(orderState))
						{
							throwException("工单已经发布不允许更新");
						}
						// 若未发布，则需要更新工单数量
						else
						{
							int result = getFunctions().dialogYesNo(
								"确认",
								"数据:\n日期：" + plannedDateStr + "\n产品：" + partDescription + "\n数量："
									+ quantityStr + "\n已经存在并且已经生成了工单，\n是否更新");
							if (result == 6)
							{
								Response response = getFunctions().getUserTransaction();
								if (response.isError())
								{
									throw new MESException(getMessage("ERROR_29"), MODULE_PM, "导入生产计划");
								}
								UserTransaction userTransaction = (UserTransaction) response
									.getResult();
								response = userTransaction.begin();
								if (response.isError())
								{
									throw new MESException(getMessage("ERROR_29"), MODULE_PM, "导入生产计划");
								}
								try
								{
									// 判断生产数量与工单数量是否相等，若不相等，则需要更新工单数量
									if (uiOrder.getPlannedQuantityValue().compareTo(new BigDecimal(plannedQty)) != 0)
									{
										uiOrder.changePlannedQty(new BigDecimal(plannedQty));
									}

									//更新计划数量
									atRow.setValue(
										AT_COLUMN_PM_WORK_PLAN_COMMENT, comment);
									atRow.setValue(
										AT_COLUMN_PM_WORK_PLAN_PLANNED_DATE, plannedDate);
									atRow.setValue(
										AT_COLUMN_PM_WORK_PLAN_PLANNED_QTY, plannedQty);
									atRow.setValue(
										AT_COLUMN_PM_WORK_PLAN_IS_TEST, isTest);
									atRow.setValue(
										AT_COLUMN_PM_WORK_PLAN_IMPORT_DATE, getTrxTime());
									atRow.setValue(
										AT_COLUMN_PM_WORK_PLAN_PRODUCTION_LINE, productionLineName);
									atRow.setValue(
										AT_COLUMN_PM_WORK_PLAN_PART_DESCRIPTION, partDescription);
									atRow.setValue(
										AT_COLUMN_PM_WORK_PLAN_SAP_CODE, partNumber);
									response = atRow.save(
										null, null, null);
									if (response.isError())
									{
										throwException(response.getFirstErrorMessage());
									}

									response = userTransaction.commit();
									if (response.isError())
									{
										throwException("ERROR_29");
									}
									else
									{
										updateSize++;
									}
								}
								catch (Exception e)
								{
									e.printStackTrace();
									userTransaction.rollback();
									throwException("导入生产计划");
								}
							}
							else
							{
								throwException("不更新数据");
							}
						}
					}
					//若没有生成工单
					else
					{
						int result = getFunctions().dialogYesNo("确认", "日期："+plannedDateStr+"\n产品："+partDescription+"\n数量："+quantityStr+"\n已经存在，是否更新");
						if(result == 6)
						{
							atRow.setValue(
								AT_COLUMN_PM_WORK_PLAN_COMMENT, comment);
							atRow.setValue(
								AT_COLUMN_PM_WORK_PLAN_PLANNED_DATE, plannedDate);
							atRow.setValue(
								AT_COLUMN_PM_WORK_PLAN_PLANNED_QTY, plannedQty);
							atRow.setValue(
								AT_COLUMN_PM_WORK_PLAN_IS_TEST, isTest);
							atRow.setValue(
								AT_COLUMN_PM_WORK_PLAN_IMPORT_DATE, getTrxTime());
							atRow.setValue(
								AT_COLUMN_PM_WORK_PLAN_PRODUCTION_LINE, productionLineName);
							atRow.setValue(
								AT_COLUMN_PM_WORK_PLAN_PART_DESCRIPTION, partDescription);
							atRow.setValue(
								AT_COLUMN_PM_WORK_PLAN_SAP_CODE, partNumber);
							Response response = atRow.save(null, null, null);
							if(response.isOk())
							{
								updateSize++;
							}
							else
							{
								throwException(response.getFirstErrorMessage());
							}
						}
						else
						{
							throwException("不更新数据");
						}
					}
				}
				
			}
			catch (Exception e)
			{
				e.printStackTrace();
				errorSize++;
			}
		}

		// return "共导入数据" + totalSize + "条，其中新建数据" + creationNum + "条，更新数据" +
		// updateNum
		// + "条，失败" + (totalSize - creationNum - updateNum) + "条";
		String str = (getMessage("ERROR_1") + totalSize + getMessage("ERROR_2") + createSize
			+ getMessage("ERROR_3") + updateSize + getMessage("ERROR_4") + errorSize
			+ getMessage("ERROR_5")+"。").replaceAll("，", ",\n");
		return str;
	}

	/**
	 * 验证是否实验工单
	 */
	private void validateIsTest(String isTestStr) throws Exception
	{
		if(StringUtils.isNotNull(isTestStr))
		{
			if("是".equals(isTestStr) || "否".equals(isTestStr))
			{
				
			}
			else
			{
				throwException("导入格式不准确");
			}
		}
	}

	/**
	 * 验证数量
	 */
	private void validateQty(String quantityStr) throws Exception
	{
		try{
			BigDecimal qty = new BigDecimal(quantityStr);
			if(qty.compareTo(BigDecimal.ZERO)<=0)
			{
				throwException("导入格式不准确");
			}
		}catch (Exception e) {
			throwException("导入格式不准确");
		}
	}

	/**
	 * 验证产品
	 */
	private void validateProduct(String partNumber, String partDescription) throws Exception
	{
		PartFilter partFilter = getFunctions().createPartFilter();
		partFilter.forPartNameEqualTo(partNumber);
		partFilter.forDescriptionEqualTo(partDescription);
		int count = getFunctions().getFilteredPartCount(partFilter);
		if(count == 0)
		{
			throwException("导入格式不准确");
		}
	}

	/**
	 * 验证产线
	 */
	private void validateProductionLine(String productionLineName) throws Exception
	{
		ProductionLine productionLine = getFunctions().getProductionLineByName(productionLineName);
		if(productionLine == null)
		{
			throwException("导入格式不准确");
		}
	}

	/**
	 * 验证计划时间
	 */
	private void validatePlannedDate(String plannedDateStr) throws Exception
	{
		System.out.println(plannedDateStr);
		String[] plannedDateArray = plannedDateStr.split("/");
		if(plannedDateArray.length != 3)
		{
			throwException("导入格式不准确");
		}
		String year = plannedDateArray[0];
		String month = plannedDateArray[1];
		String day = plannedDateArray[2];
		if(year.length() != 4 || month.length() != 2 || day.length() != 2)
		{
			throwException("导入格式不准确");
		}
		
		Integer yearInt = Integer.parseInt(year);
		Integer monthInt = Integer.parseInt(month);
		Integer dayInt = Integer.parseInt(day);
		if(yearInt<1 || yearInt>9999)
		{
			throwException("导入格式不准确");
		}
		
		if(monthInt<1 || monthInt>12)
		{
			throwException("导入格式不准确");
		}
		
		if(dayInt<0 || dayInt>31)
		{
			throwException("导入格式不准确");
		}
	}

	/**
	 * 查询生产计划
	 * @param plannedTime		计划日期
	 * @param partDescrpiton	产品名称
	 * @param productionLine	产线
	 */
	public Vector<WorkPlan> searchWorkPlans(Time plannedTimeStart,Time plannedTimeEnd,String partNumber,String productionLineName) throws MESException
	{
		try{
			Vector<WorkPlan> pmWorkPlans = new Vector<WorkPlan>();
			ATRowFilter atRowFilter = getFunctions().createATRowFilter(IATConstants.AT_TABLE_PM_WORK_PLAN);
			if(plannedTimeStart != null)
			{
				atRowFilter.forColumnNameGreaterThanOrEqualTo(AT_COLUMN_PM_WORK_PLAN_PLANNED_DATE, getDayStart(plannedTimeStart));
			}
			if(plannedTimeEnd != null)
			{
				atRowFilter.forColumnNameLessThanOrEqualTo(AT_COLUMN_PM_WORK_PLAN_PLANNED_DATE, getDayEnd(plannedTimeEnd));
			}
			if(StringUtils.isNotNull(partNumber))
			{
				atRowFilter.forColumnNameContaining(AT_COLUMN_PM_WORK_PLAN_SAP_CODE, partNumber);
			}
			
			if(productionLineName != null){
				if(StringUtils.isNotNull(productionLineName))
				{
					atRowFilter.forColumnNameContaining(AT_COLUMN_PM_WORK_PLAN_PRODUCTION_LINE, productionLineName);
				}
			}
			
			Vector atRows = getFunctions().getFilteredATRows(atRowFilter, false);
			for (int i = 0; i < atRows.size(); i++)
			{
				pmWorkPlans.add(new WorkPlan((ATRow) atRows.get(i)));
			}
			return pmWorkPlans;
		}catch (Exception e) {
			throw new MESException(e, MODULE_PM, "查询生产计划");
		}
	}
	
	/**
	 * 查询计划日期某产线某产品是否唯一
	 * @param plannedTime			计划日期
	 * @param sapCode				产品代码
	 * @param productionLineName	产线名称
	 */
	private ATRow searchWorkPlans(Time plannedTime,String sapCode,String productionLineName) throws Exception
	{
		ATRowFilter atRowFilter = getFunctions().createATRowFilter(
			IATConstants.AT_TABLE_PM_WORK_PLAN);
		if (plannedTime != null)
		{
			atRowFilter.forColumnNameGreaterThanOrEqualTo(
				AT_COLUMN_PM_WORK_PLAN_PLANNED_DATE, getDayStart(plannedTime));
			atRowFilter.forColumnNameLessThanOrEqualTo(
				AT_COLUMN_PM_WORK_PLAN_PLANNED_DATE, getDayEnd(plannedTime));
		}
		else
		{
//			throwException("计划日期不允许为空");
			throwException("ERROR_7");
		}

		if (StringUtils.isNotNull(sapCode))
		{
			atRowFilter.forColumnNameEqualTo(
				AT_COLUMN_PM_WORK_PLAN_SAP_CODE, sapCode);
		}
		else
		{
//			throwException("产品代码不允许为空");
			throwException("ERROR_8");
		}

		if (StringUtils.isNotNull(productionLineName))
		{
			atRowFilter.forColumnNameEqualTo(
				AT_COLUMN_PM_WORK_PLAN_PRODUCTION_LINE, productionLineName);
		}
		else
		{
//			throwException("产线名称不允许为空");
			throwException("ERROR_9");
		}

		Vector atRows = getFunctions().getFilteredATRows(
			atRowFilter, false);
		if (atRows != null && atRows.size() > 0)
		{
			return (ATRow) atRows.firstElement();
		}
		return null;
	}
	
	/**
	 * 导出到Excel
	 * @param workPlans
	 * @throws MESException
	 */
	public void exportToExcel(Vector<WorkPlan> workPlans,String workPlanDir) throws MESException
	{
		
		try
		{
			//sapCode和物料说明对应cache
			HashMap<String, String> partMapCache = new HashMap<String, String>();
			
			//时间和计划对应表
			TreeMap<String, ArrayList<WorkPlan>> timeMap = new TreeMap<String, ArrayList<WorkPlan>>(new Comparator<String>()
			{

				@Override
				public int compare(String o1, String o2)
					{
						try
						{
							SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
							return sdf.parse(
								o1).compareTo(
								sdf.parse(o2));
						}
						catch (Exception e)
						{
							return 0;
						}
					}
			});
			
			//初始化标题头 key为产线 String为SapCode
			HashMap<String, ArrayList<String>> headers = new HashMap<String, ArrayList<String>>();
			for (int i = 0; i < workPlans.size(); i++)
			{
				WorkPlan workPlan = workPlans.get(i);
				String productionLineName = workPlan.getProductionLine();
				String sapCode = workPlan.getSapCode();
				String partDescription = workPlan.getPartDescription();
				String plannedDate = workPlan.getPlannedDate();
				
				partMapCache.put(productionLineName+sapCode, partDescription);
				
				//初始化标题头
				if(!headers.containsKey(productionLineName)){
					headers.put(productionLineName, new ArrayList<String>());
				}
				
				ArrayList<String> values = headers.get(productionLineName);
				if(!values.contains(sapCode))
					values.add(sapCode);
				
				//将计划按日期排序
				if(!timeMap.containsKey(plannedDate)){
					timeMap.put(plannedDate, new ArrayList<WorkPlan>());
				}
				
				ArrayList<WorkPlan> pmWorkPlans = timeMap.get(plannedDate);
				if(!pmWorkPlans.contains(workPlan))
					pmWorkPlans.add(workPlan);
			}
			
			//产品横坐标对应表
			HashMap<String, Integer> locationMap = new HashMap<String, Integer>();
			
			//横坐标
			int column = partMapCache.size()+1;
			
			//纵坐标
			int row = timeMap.size()*2+4;
			
			//生成数据
			String[][] data = new String[row][column];
			
			//生成标题头
			data[0][0] = getMessage("ERROR_10");
//			data[0][0] = "周生产计划表";
			data[1][0] = getMessage("ERROR_11");
				//"生产线";
			data[2][0] = getMessage("ERROR_12");
				//"产品名称";
			data[3][0] = getMessage("ERROR_13");
				//"SAP代码";
			
			Set<String> keySet = headers.keySet();
			
			int headerCol = 1;
			for (String key : keySet)
			{
				ArrayList<String> sapCodes = headers.get(key);
				for (int i = 0; i < sapCodes.size(); i++)
				{
					String sapCode = sapCodes.get(i);
					data[1][headerCol] = key;
					data[2][headerCol] = partMapCache.get(key+sapCode);
					data[3][headerCol] = sapCode;
					locationMap.put(key+sapCode, headerCol);
					headerCol++;
				}
			}
			
			//第四行开始生成数据
			int currentRow = 4;
			
			//生成数据
			Set<String> keys = timeMap.keySet();
			SimpleDateFormat simpleDateFormatOld = new SimpleDateFormat("yyyy-MM-dd");
			SimpleDateFormat simpleDateFormatNew = new SimpleDateFormat("dd/MMM/yy",Locale.ENGLISH);
			for (String key : keys)
			{
				
				
				data[currentRow][0] = simpleDateFormatNew.format(simpleDateFormatOld.parse(key));
				data[currentRow+1][0] = getMessage("ERROR_14");
					//"是否实验订单";
				
				ArrayList<WorkPlan> rowDatas = timeMap.get(key);
				for (int i = 0; i < rowDatas.size(); i++)
				{
					WorkPlan workPlan = rowDatas.get(i);
					String sapCode = workPlan.getSapCode();
					Float qty = workPlan.getPlannedQty().floatValue();
					String productionLine = workPlan.getProductionLine();
					Integer col = locationMap.get(productionLine+sapCode);
					data[currentRow][col] = qty.toString();
					Boolean isTest = WORK_PLAN_IS_TEST_TRUE.equals(workPlan.getIsTest());
					if(isTest)
					{
						data[currentRow+1][col] = "Y";
					}
					else
					{
						data[currentRow+1][col] = "N";
					}
				}
				currentRow+=2;
			}
			
			//将数据转换为Excel
			toExcel(workPlanDir,data,WORK_PLAN_WEEK_PLAN_SHEET_NAME);
		}
		catch (Exception e)
		{
			e.printStackTrace();
			throw new MESException(e, MODULE_PM, "导出周生产计划表");
		}
	}
	
	/**
	 * 生成一个UIOrder
	 */
	public UIOrder createUIOrder()
	{
		Order order = getFunctions().createWorkOrder(getTrxTime().toString());
		OrderItem orderItem = getFunctions().createOrderItem();
		order.addOrderItem(orderItem);
		order.setOrderState(IOrderState.CREATED);
		return new UIOrder(order,getFunctions());
	}
	
	/**
	 * 更改工单状态
	 * @param order			工单
	 * @param orderState	工单状态
	 */
	private Response changeOrderStatus(Order order, String orderState)
	{
		order.setOrderState(orderState);
		return order.save();
	}
	
	/**
	 * 更改工单状态
	 * @param order			工单
	 * @param orderState	工单状态
	 */
	private Response changeOrderStatus(UIOrder uiOrder, String orderState)
	{
		Order order = uiOrder.getObject();
		return changeOrderStatus(order, orderState);
	}
	
	/**
	 * 停止投料
	 */
	public void stopMaterial(UIOrder uiOrder) throws Exception
	{
		try
		{
			String orderState = uiOrder.getOrderState();
			if(IOrderState.STARTED.equals(orderState))
			{
				changeOrderStatus(uiOrder, IOrderState.STOP_MATERIAL);
			}
			else
			{
//				throwException("非启动状态的工单不允许投料");
				throwException("ERROR_15");
			}
		}catch (Exception e) {
			throw new MESException(e, MODULE_PM, "停止投料");
		}
	}
	
	/**
	 * 停止生产
	 * @param uiOrder
	 * @throws Exception
	 */
	public void stopProduce(UIOrder uiOrder) throws Exception
	{
		try
		{
			String orderState = uiOrder.getOrderState();
			if(IOrderState.STARTED.equals(orderState))
			{
				changeOrderStatus(uiOrder, IOrderState.STOP_PRODUCE);
			}
			else
			{
				throwException("ERROR_16");
//				throwException("非启动状态的工单不允许停止生产");
			}
		}catch (Exception e) {
			throw new MESException(e, MODULE_PM, "停止生产");
		}
	}
	
	/**
	 * 恢复生产
	 */
	public void resumeProduce(UIOrder uiOrder) throws Exception
	{
		try
		{
			String orderState = uiOrder.getOrderState();
			if(IOrderState.STOP_MATERIAL.equals(orderState)||IOrderState.STOP_PRODUCE.equals(orderState))
			{
				Time startedTime = uiOrder.getStartedTime();
				if(startedTime != null && startedTime.addDays(1).compareTo(getTrxTime())<0)
				{
//					throwException("超过一天不允许生产");
					throwException("ERROR_17");
				}
				else
				{
					changeOrderStatus(uiOrder, IOrderState.STARTED);
				}
			}
			else
			{
				throwException("ERROR_18");
//				throwException("非停止投料、停止生产状态的工单不允许停止生产");
			}
		}catch (Exception e) {
			throw new MESException(e, MODULE_PM, "恢复生产");
		}
	}
	
	/**
	 * 发布工单
	 */
	public void publishOrder(UIOrder uiOrder) throws Exception
	{
		try
		{
			String orderState = uiOrder.getOrderState();
			if(IOrderState.CREATED.equals(orderState))
			{
				if(!"OK".equals(uiOrder.getObject().getAddress1()))
				{
					throwException("ERROR_124");
				}
				//向WMS发送数据
				if(!isDebug)
				{
					sendOrderToWMS(uiOrder);
				}
				//更新发布时间
				Order order = uiOrder.getObject();
				order.setUDT(getTrxTime(), UDT_ORDER_PUBLISH_DATE);
				//更新工单状态
				changeOrderStatus(uiOrder, IOrderState.PUBLISHED);
				
				// 将工单发送至SAP
				// TODO
			}
			else
			{
				throwException("ERROR_19");
//				throwException("只有新建状态的工单才能够发布");
			}
		}
		catch (Exception e) 
		{
			throw new MESException(e, MODULE_PM, "发布工单");
		}
	}
	
	/**
	 * 工单关闭
	 */
	public void closeProduce(UIOrder uiOrder) throws Exception
	{
		try
		{
			//更新工单状态
			changeOrderStatus(uiOrder, IOrderState.CLOSED);
		}
		catch (Exception e) 
		{
			throw new MESException(e, MODULE_PM, "发布工单");
		}
	}
	
	/**
	 * 将工单发送给WMS
	 */
	private void sendOrderToWMS(UIOrder uiOrder) throws Exception
	{
		try
		{
			Lot lot = uiOrder.getLot();
			BillOfMaterials billOfMaterials = lot.getBillOfMaterials();
			Vector bomItems = billOfMaterials.getBomItems();
			String orderName = uiOrder.getOrderName();
			String plannedDate = uiOrder.getPlannedTime();
			
			Hashtable<String, ArrayList<Object>> wmdsData = new Hashtable<String, ArrayList<Object>>();
			wmdsData.put(
				ISystemDataConstants.WMDS_OPERATOR, toTransferValue(NULL));
			wmdsData.put(
				ISystemDataConstants.WMDS_OPERATE, toTransferValue("ADD_PREOUTBILL"));
			
			Hashtable<String, ArrayList<Object>> requestBillData = new Hashtable<String, ArrayList<Object>>();
			requestBillData.put(ISystemDataConstants.WBS_REQUEST_BILL_BILL_NO,toTransferValue(orderName));
			requestBillData.put(ISystemDataConstants.WBS_REQUEST_BILL_SUPPLIER_ID,toTransferValue(NULL));
			requestBillData.put(ISystemDataConstants.WBS_REQUEST_BILL_BILL_TYPE,toTransferValue("202-60-1"));
			requestBillData.put(ISystemDataConstants.WBS_REQUEST_BILL_BILL_DATE,toTransferValue(plannedDate));
			requestBillData.put(ISystemDataConstants.REF_1,toTransferValue(NULL));
			requestBillData.put(ISystemDataConstants.REF_2,toTransferValue(NULL));
			requestBillData.put(ISystemDataConstants.REF_3,toTransferValue(NULL));
			requestBillData.put(ISystemDataConstants.REF_4,toTransferValue(NULL));
			requestBillData.put(ISystemDataConstants.REF_5,toTransferValue(NULL));
			requestBillData.put(ISystemDataConstants.WBS_REQUEST_BILL_WHSCD,toTransferValue(NULL));
			
			Hashtable<String, ArrayList<Object>> wBSBillItemData = new Hashtable<String, ArrayList<Object>>();
			ArrayList<Object> itemDatas = new ArrayList<Object>();
			for (int i = 0; i < bomItems.size(); i++)
			{
				Hashtable<String, ArrayList<Object>> itemData = new Hashtable<String, ArrayList<Object>>();
				
				BomItem bomItem = (BomItem) bomItems.get(i);
				Part part = bomItem.getPart();
				String partNumber = part.getPartNumber();
				String description = part.getDescription();
				String qtyStr = bomItem.getUDA(1);
				if(StringUtils.isNull(qtyStr))
				{
					throw new Exception("物料数量不允许为空");
				}
				BigDecimal qty = new BigDecimal(bomItem.getUDA(1));
//					bomItem.getPreciseQuantity();
				qty = qty.setScale(2, BigDecimal.ROUND_FLOOR);
				Time plannedItemTime = (Time) bomItem.getUDA(IUDADefinitions.UDA_BOM_ITEM_CONFIRM_TIME);
				String plannedItemTimeStr = DateTimeUtils.formatDate(plannedItemTime, "yyyy-MM-dd HH:mm:ss");
				itemData.put(ISystemDataConstants.WBS_REQUEST_BILL_ITEMS_BILL_NO, toTransferValue(orderName));
				itemData.put(ISystemDataConstants.WBS_REQUEST_BILL_ITEMS_SUPPLIER_ID, toTransferValue(NULL));
				itemData.put(ISystemDataConstants.WBS_REQUEST_BILL_ITEMS_SUPPLIER_NAME, toTransferValue(NULL));
				itemData.put(ISystemDataConstants.WBS_REQUEST_BILL_ITEMS_ITEM_ID, toTransferValue(partNumber));
				itemData.put(ISystemDataConstants.WBS_REQUEST_BILL_ITEMS_ITEM_NAME, toTransferValue(description));
				itemData.put(ISystemDataConstants.WBS_REQUEST_BILL_ITEMS_BILL_TYPE, toTransferValue(NULL));
				itemData.put(ISystemDataConstants.WBS_REQUEST_BILL_ITEMS_BILL_DATE, toTransferValue(plannedDate));
				itemData.put(ISystemDataConstants.WBS_REQUEST_BILL_ITEMS_IN_DATE, toTransferValue(NULL));
				
				itemData.put(ISystemDataConstants.WBS_REQUEST_BILL_ITEMS_OUT_DATE, toTransferValue(plannedItemTimeStr));
				itemData.put(ISystemDataConstants.WBS_REQUEST_BILL_ITEMS_MATERIAL_LABEL, toTransferValue(NULL));
				itemData.put(ISystemDataConstants.WBS_REQUEST_BILL_ITEMS_BATCH_NO, toTransferValue(NULL));
				itemData.put(ISystemDataConstants.WBS_REQUEST_BILL_ITEMS_QTY, toTransferValue(qty.toString()));
				itemData.put(ISystemDataConstants.REF_1,toTransferValue(NULL));
				itemData.put(ISystemDataConstants.REF_2,toTransferValue(NULL));
				itemData.put(ISystemDataConstants.REF_3,toTransferValue(NULL));
				itemData.put(ISystemDataConstants.REF_4,toTransferValue(NULL));
				itemData.put(ISystemDataConstants.REF_5,toTransferValue(NULL));
				
				itemDatas.add(itemData);
				wBSBillItemData.put("WBSBillItem",itemDatas);
				
			}
			
			requestBillData.put(ISystemDataConstants.WBS_REQUEST_BILL_ITEMS, toTransferValue(wBSBillItemData));
			
			Hashtable<String, ArrayList<Object>> WBSBillHeadData = new Hashtable<String, ArrayList<Object>>();
			WBSBillHeadData.put("WBSBillHead", toTransferValue(requestBillData));
			
			wmdsData.put(
				ISystemDataConstants.WBS_REQUEST_BILL,toTransferValue(WBSBillHeadData));
			
			String xmlStr = XMLUtils.toXMLStr(wmdsData);
			
			xmlStr = xmlStr.replaceAll("<xml>", "<WBSParam>");
			xmlStr = xmlStr.replaceAll("</xml>", "</WBSParam>");
			
			System.out.println(xmlStr);
			
			String result = MDUtils.invokeDNetWebService(
				END_POINT, NAME_SPACE, METHOD_NAME_WBS, SOAP_ACTION_WBS, PARAMETER_NAME, xmlStr);
			XmlData xmlData = XMLUtils.strToXMLData(result);
			Hashtable<String, ArrayList<Object>> data = xmlData.getData();
			result = getTransferValue(data, "Result");
			if(!"true".equals(result))
			{
				throw new Exception(getMessage("ERROR_20")+getTransferValue(data, "Message"));
			}
		}
		catch (Exception e) 
		{
			e.printStackTrace();
			throw new MESException(e, MODULE_PM, "发布工单");
		}
	}
	
	/**
	 * 将物料确认发送给WMS
	 * @param material		物料
	 * @param uiOrder		工单
	 * @param lot			批次
	 * @throws MESException
	 */
	public void sendMaterialToWMS(Lot material) throws MESException
	{
		Vector<Lot> materials = new Vector<Lot>();
		materials.add(material);
		sendMaterialsToWMS(materials);
	}
	
	/**
	 * 将物料主数据发送给WMS
	 * @param parts			物料主数据
	 * @param method		0:新建 1：更新 2：删除
	 */
	public void sendPartsToWMS(Vector<Part> parts,int method) throws MESException
	{
		try
		{
			String methodStr = "ADD_MATERIAL";
			if(method == 1)
			{
				methodStr = "UPDATE_MATERIAL";
			}
			else if(method == 2)
			{
				methodStr = "DELETE_MATERIAL";
			}
			
			Hashtable<String, ArrayList<Object>> sendData = new Hashtable<String, ArrayList<Object>>();
			Hashtable<String, ArrayList<Object>> wmdsData = new Hashtable<String, ArrayList<Object>>();
			wmdsData.put(
				ISystemDataConstants.WMDS_OPERATOR, toTransferValue(NULL));
			wmdsData.put(
				ISystemDataConstants.WMDS_OPERATE, toTransferValue(methodStr));
			
			ArrayList<Object> itemDatas = new ArrayList<Object>();
			for (int i = 0; i < parts.size(); i++)
			{
				Hashtable<String, ArrayList<Object>> itemData = new Hashtable<String, ArrayList<Object>>();
				Part part = parts.get(i);
				String partNumber = part.getPartNumber();
				String description = part.getDescription();
				String item_group = part.getUDA(UDA_PART_ITEM_GROUP_NAME) == null ? NULL : (String) part
					.getUDA(UDA_PART_ITEM_GROUP_NAME);
				Float each_weight = (Float) part.getUDA(UDA_PART_WEIGHT);
				String uom = StringUtils.isNull(part.getUnitOfMeasure())?NULL:part.getUnitOfMeasure();
				String spec = (String) part.getUDA(UDA_PART_SPEC);
				String class1 = part.getUDA(UDA_PART_CLASS1) == null ? NULL : (String) part
					.getUDA(UDA_PART_CLASS1);
				String class2 = part.getUDA(UDA_PART_CLASS2) == null ? NULL : (String) part
					.getUDA(UDA_PART_CLASS2);
				String class3 = part.getUDA(UDA_PART_CLASS3) == null ? NULL : (String) part
					.getUDA(UDA_PART_CLASS3);
				String class4 = part.getUDA(UDA_PART_CLASS4) == null ? NULL : (String) part
					.getUDA(UDA_PART_CLASS4);
				String class5 = part.getUDA(UDA_PART_CLASS5) == null ? NULL : (String) part
					.getUDA(UDA_PART_CLASS5);
				Long valid_days = (Long) part.getUDA(UDA_PART_VALID_PERIOD);
				Float minLevel = (Float) part.getUDA(UDA_PART_MIN_LEVEL);
				Float maxLevel = (Float) part.getUDA(UDA_PART_MAX_LEVEL);
				Long isOil = (Long) part.getUDA(UDA_PART_IS_OIL);
				Long isCO2 = (Long) part.getUDA(UDA_PART_IS_CO2);
				String overRateStr = NULL;
				MeasuredValue overRate = (MeasuredValue) part.getUDA(UDA_PART_OVER_RATE);
				if (overRate != null)
					overRateStr = overRate.getValue().setScale(
						2, 3).toString();
				Long docEntry = (Long) part.getUDA(UDA_PART_DOCENTRY);
				Long isOutside = (Long) part.getUDA(UDA_PART_SUPPLIER);
				Long tray_qty = (Long) part.getUDA(UDA_PART_TRAY_QUANTITY);
				Hashtable<String, ArrayList<Object>> wmdsItem = new Hashtable<String, ArrayList<Object>>();
				wmdsItem.put(
					ISystemDataConstants.WMDS_WMDSITEM_KEY, toTransferValue(partNumber));
				wmdsItem.put(
					ISystemDataConstants.WMDS_WMDSITEM_VALUE, toTransferValue(description));
				wmdsItem.put(
					ISystemDataConstants.WMDS_WMDSITEM_ITEM_TYPE, toTransferValue(item_group));
				wmdsItem.put(
					ISystemDataConstants.WMDS_WMDSITEM_REF1, toTransferValue(each_weight));
				wmdsItem.put(
					ISystemDataConstants.WMDS_WMDSITEM_REF2, toTransferValue(uom));
				wmdsItem.put(
					ISystemDataConstants.WMDS_WMDSITEM_REF3, toTransferValue(spec));
				wmdsItem.put(
					ISystemDataConstants.WMDS_WMDSITEM_REF4, toTransferValue(class1));
				wmdsItem.put(
					ISystemDataConstants.WMDS_WMDSITEM_REF5, toTransferValue(class2));
				wmdsItem.put(
					ISystemDataConstants.WMDS_WMDSITEM_REF6, toTransferValue(class3));
				wmdsItem.put(
					ISystemDataConstants.WMDS_WMDSITEM_REF7, toTransferValue(class4));
				wmdsItem.put(
					ISystemDataConstants.WMDS_WMDSITEM_REF8, toTransferValue(class5));
				wmdsItem.put(
					ISystemDataConstants.WMDS_WMDSITEM_REF9, toTransferValue(valid_days));
				wmdsItem.put(
					ISystemDataConstants.WMDS_WMDSITEM_REF10, toTransferValue(minLevel));
				wmdsItem.put(
					ISystemDataConstants.WMDS_WMDSITEM_REF11, toTransferValue(maxLevel));
				wmdsItem.put(
					ISystemDataConstants.WMDS_WMDSITEM_REF12, toTransferValue(isOil));
				wmdsItem.put(
					ISystemDataConstants.WMDS_WMDSITEM_REF13, toTransferValue(isCO2));
				wmdsItem.put(
					ISystemDataConstants.WMDS_WMDSITEM_REF14, toTransferValue(overRateStr));
				wmdsItem.put(
					ISystemDataConstants.WMDS_WMDSITEM_REF15, toTransferValue(isOutside));
				wmdsItem.put(
					ISystemDataConstants.WMDS_WMDSITEM_REF16, toTransferValue(tray_qty));
				wmdsItem.put(
					ISystemDataConstants.WMDS_WMDSITEM_DESCRIPTION, toTransferValue(docEntry));
				itemData.put(
					ISystemDataConstants.WMDS_WMDSITEM, toTransferValue(wmdsItem));
				
				itemDatas.add(itemData);
			}
			wmdsData.put(
				ISystemDataConstants.WMDS_ITEMS, itemDatas);
			
			sendData.put(
				ISystemDataConstants.WMDS, toTransferValue(wmdsData));

			String xmlStr = XMLUtils.toXMLStr(sendData);

			xmlStr = xmlStr.replaceAll(
				"<xml>", "");
			xmlStr = xmlStr.replaceAll(
				"</xml>", "");

			System.out.println(xmlStr);
			String result = MDUtils.invokeDNetWebService(
				END_POINT, NAME_SPACE, METHOD_NAME_WMDS, SOAP_ACTION_WMDS, PARAMETER_NAME, xmlStr);
			System.out.println(result);
			XmlData xmlData = XMLUtils.strToXMLData(result);
			Hashtable<String, ArrayList<Object>> data = xmlData.getData();
			String message = getTransferValue(data, ISystemDataConstants.WMDS_MESSAGE);
			result = getTransferValue(data, ISystemDataConstants.WMDS_RESULT);
			if(!"true".equals(result))
			{
				throw new Exception(getMessage("ERROR_21")+message);
			}
		}
		catch (Exception e)
		{
			throw new MESException(e, MODULE_PM, "下发物料到WMS");
		}
	}
	
	/**
	 * 将物料主数据发送给WMS
	 * @param part		物料主数据
	 * @param method	0:新建 1：更新 2：删除
	 */
	public void sendPartToWMS(Part part,int method) throws MESException
	{
		Vector<Part> parts = new Vector<Part>();
		parts.add(part);
		sendPartsToWMS(parts, method);
	}
	
	/**
	 * 将物料确认发送给WMS
	 * @param materials		物料
	 * @param uiOrder		工单
	 * @param lot			批次
	 * @throws MESException
	 */
	public void sendMaterialsToWMS(Vector<Lot> materials) throws MESException
	{
		try
		{
			if(isDebug)
			{
				return;
			}
			Hashtable<String, ArrayList<Object>> wmdsData = new Hashtable<String, ArrayList<Object>>();
			wmdsData.put(
				ISystemDataConstants.WMDS_OPERATOR, toTransferValue(NULL));
			wmdsData.put(
				ISystemDataConstants.WMDS_OPERATE, toTransferValue("MESmaterialReceiptConfirm"));
			
			Hashtable<String, ArrayList<Object>> requestBillData = new Hashtable<String, ArrayList<Object>>();
			requestBillData.put(ISystemDataConstants.WBS_REQUEST_BILL_BILL_NO,toTransferValue(NULL));
			requestBillData.put(ISystemDataConstants.WBS_REQUEST_BILL_SUPPLIER_ID,toTransferValue(NULL));
			requestBillData.put(ISystemDataConstants.WBS_REQUEST_BILL_BILL_TYPE,toTransferValue(NULL));
			requestBillData.put(ISystemDataConstants.WBS_REQUEST_BILL_BILL_DATE,toTransferValue(NULL));
			requestBillData.put(ISystemDataConstants.REF_1,toTransferValue(NULL));
			requestBillData.put(ISystemDataConstants.REF_2,toTransferValue(NULL));
			requestBillData.put(ISystemDataConstants.REF_3,toTransferValue(NULL));
			requestBillData.put(ISystemDataConstants.REF_4,toTransferValue(NULL));
			requestBillData.put(ISystemDataConstants.REF_5,toTransferValue(NULL));
			requestBillData.put(ISystemDataConstants.WBS_REQUEST_BILL_WHSCD,toTransferValue(NULL));
			
			Hashtable<String, ArrayList<Object>> wBSBillItemData = new Hashtable<String, ArrayList<Object>>();
			ArrayList<Object> itemDatas = new ArrayList<Object>();
			for (int i = 0; i < materials.size(); i++)
			{
				Hashtable<String, ArrayList<Object>> itemData = new Hashtable<String, ArrayList<Object>>();
				
				Lot lot = (Lot) materials.get(i);
				String lotName = lot.getName();
				itemData.put(ISystemDataConstants.WBS_REQUEST_BILL_ITEMS_BILL_NO, toTransferValue(NULL));
				itemData.put(ISystemDataConstants.WBS_REQUEST_BILL_ITEMS_SUPPLIER_ID, toTransferValue(NULL));
				itemData.put(ISystemDataConstants.WBS_REQUEST_BILL_ITEMS_SUPPLIER_NAME, toTransferValue(NULL));
				itemData.put(ISystemDataConstants.WBS_REQUEST_BILL_ITEMS_ITEM_ID, toTransferValue(NULL));
				itemData.put(ISystemDataConstants.WBS_REQUEST_BILL_ITEMS_ITEM_NAME, toTransferValue(NULL));
				itemData.put(ISystemDataConstants.WBS_REQUEST_BILL_ITEMS_BILL_TYPE, toTransferValue(NULL));
				itemData.put(ISystemDataConstants.WBS_REQUEST_BILL_ITEMS_BILL_DATE, toTransferValue(NULL));
				itemData.put(ISystemDataConstants.WBS_REQUEST_BILL_ITEMS_IN_DATE, toTransferValue(NULL));
				
				itemData.put(ISystemDataConstants.WBS_REQUEST_BILL_ITEMS_OUT_DATE, toTransferValue(NULL));
				itemData.put(ISystemDataConstants.WBS_REQUEST_BILL_ITEMS_MATERIAL_LABEL, toTransferValue(lotName));
				itemData.put(ISystemDataConstants.WBS_REQUEST_BILL_ITEMS_BATCH_NO, toTransferValue(NULL));
				itemData.put(ISystemDataConstants.WBS_REQUEST_BILL_ITEMS_QTY, toTransferValue(0));
				itemData.put(ISystemDataConstants.REF_1,toTransferValue(NULL));
				itemData.put(ISystemDataConstants.REF_2,toTransferValue(NULL));
				itemData.put(ISystemDataConstants.REF_3,toTransferValue(NULL));
				itemData.put(ISystemDataConstants.REF_4,toTransferValue(NULL));
				itemData.put(ISystemDataConstants.REF_5,toTransferValue(NULL));
				
				itemDatas.add(itemData);
				wBSBillItemData.put("WBSBillItem",itemDatas);
				
			}
			
			requestBillData.put(ISystemDataConstants.WBS_REQUEST_BILL_ITEMS, toTransferValue(wBSBillItemData));
			
			Hashtable<String, ArrayList<Object>> WBSBillHeadData = new Hashtable<String, ArrayList<Object>>();
			WBSBillHeadData.put("WBSBillHead", toTransferValue(requestBillData));
			
			wmdsData.put(
				ISystemDataConstants.WBS_REQUEST_BILL,toTransferValue(WBSBillHeadData));
			
			String xmlStr = XMLUtils.toXMLStr(wmdsData);
			
			xmlStr = xmlStr.replaceAll("<xml>", "<WBSParam>");
			xmlStr = xmlStr.replaceAll("</xml>", "</WBSParam>");
			
			System.out.println(xmlStr);
			
			String result = MDUtils.invokeDNetWebService(
				END_POINT, NAME_SPACE, METHOD_NAME_WBS, SOAP_ACTION_WBS, PARAMETER_NAME, xmlStr);
			XmlData xmlData = XMLUtils.strToXMLData(result);
			Hashtable<String, ArrayList<Object>> data = xmlData.getData();
			result = getTransferValue(data, "Result");
			if(!"true".equals(result))
			{
				throw new Exception(getMessage("ERROR_22")+getTransferValue(data, "Message"));
			}
		}
		catch (Exception e) 
		{
			throw new MESException(e, MODULE_PM, "发布工单");
		}
	}
	
	/**
	 * 将油的消耗发送给WMS
	 * @param partNumber	物料编码
	 * @param qty			数量
	 */
	public void sendOilToWMS(String partNumber,double qty,String orderNumber,String productionLine) throws MESException
	{
		try
		{
			if(isDebug)
			{
				return;
			}
			Hashtable<String, ArrayList<Object>> wmdsData = new Hashtable<String, ArrayList<Object>>();
			wmdsData.put(
				ISystemDataConstants.WMDS_OPERATOR, toTransferValue(NULL));
			wmdsData.put(
				ISystemDataConstants.WMDS_OPERATE, toTransferValue("ADD_PREOUTBILL"));

			Hashtable<String, ArrayList<Object>> requestBillData = new Hashtable<String, ArrayList<Object>>();
			requestBillData.put(
				ISystemDataConstants.WBS_REQUEST_BILL_BILL_NO, toTransferValue(orderNumber));
			requestBillData.put(
				ISystemDataConstants.WBS_REQUEST_BILL_SUPPLIER_ID, toTransferValue(NULL));
			requestBillData.put(
				ISystemDataConstants.WBS_REQUEST_BILL_BILL_TYPE, toTransferValue("OilConsume"));
			requestBillData.put(
				ISystemDataConstants.WBS_REQUEST_BILL_BILL_DATE, toTransferValue(DateTimeUtils.formatDate(getTrxTime(), IDateFormatConstants.DATE_TIME_FORMAT_DAY)));
			requestBillData.put(
				ISystemDataConstants.REF_1, toTransferValue(productionLine));
			requestBillData.put(
				ISystemDataConstants.REF_2, toTransferValue(NULL));
			requestBillData.put(
				ISystemDataConstants.REF_3, toTransferValue(NULL));
			requestBillData.put(
				ISystemDataConstants.REF_4, toTransferValue(NULL));
			requestBillData.put(
				ISystemDataConstants.REF_5, toTransferValue(NULL));
			requestBillData.put(
				ISystemDataConstants.WBS_REQUEST_BILL_WHSCD, toTransferValue(NULL));

			Hashtable<String, ArrayList<Object>> wBSBillItemData = new Hashtable<String, ArrayList<Object>>();
			Hashtable<String, ArrayList<Object>> itemData = new Hashtable<String, ArrayList<Object>>();

			itemData.put(
				ISystemDataConstants.WBS_REQUEST_BILL_ITEMS_BILL_NO, toTransferValue(NULL));
			itemData.put(
				ISystemDataConstants.WBS_REQUEST_BILL_ITEMS_SUPPLIER_ID, toTransferValue(NULL));
			itemData.put(
				ISystemDataConstants.WBS_REQUEST_BILL_ITEMS_SUPPLIER_NAME, toTransferValue(NULL));
			itemData.put(
				ISystemDataConstants.WBS_REQUEST_BILL_ITEMS_ITEM_ID, toTransferValue(partNumber));
			itemData.put(
				ISystemDataConstants.WBS_REQUEST_BILL_ITEMS_ITEM_NAME, toTransferValue(NULL));
			itemData.put(
				ISystemDataConstants.WBS_REQUEST_BILL_ITEMS_BILL_TYPE, toTransferValue(NULL));
			itemData.put(
				ISystemDataConstants.WBS_REQUEST_BILL_ITEMS_BILL_DATE, toTransferValue(NULL));
			itemData.put(
				ISystemDataConstants.WBS_REQUEST_BILL_ITEMS_IN_DATE, toTransferValue(NULL));

			itemData.put(
				ISystemDataConstants.WBS_REQUEST_BILL_ITEMS_OUT_DATE, toTransferValue(NULL));
			itemData.put(
				ISystemDataConstants.WBS_REQUEST_BILL_ITEMS_MATERIAL_LABEL, toTransferValue(NULL));
			itemData.put(
				ISystemDataConstants.WBS_REQUEST_BILL_ITEMS_BATCH_NO, toTransferValue(NULL));
			itemData.put(
				ISystemDataConstants.WBS_REQUEST_BILL_ITEMS_QTY, toTransferValue(qty));
			itemData.put(
				ISystemDataConstants.REF_1, toTransferValue(NULL));
			itemData.put(
				ISystemDataConstants.REF_2, toTransferValue(NULL));
			itemData.put(
				ISystemDataConstants.REF_3, toTransferValue(NULL));
			itemData.put(
				ISystemDataConstants.REF_4, toTransferValue(NULL));
			itemData.put(
				ISystemDataConstants.REF_5, toTransferValue(NULL));

			wBSBillItemData.put(
				"WBSBillItem", toTransferValue(itemData));

			requestBillData.put(
				ISystemDataConstants.WBS_REQUEST_BILL_ITEMS, toTransferValue(wBSBillItemData));

			Hashtable<String, ArrayList<Object>> WBSBillHeadData = new Hashtable<String, ArrayList<Object>>();
			WBSBillHeadData.put(
				"WBSBillHead", toTransferValue(requestBillData));

			wmdsData.put(
				ISystemDataConstants.WBS_REQUEST_BILL, toTransferValue(WBSBillHeadData));

			String xmlStr = XMLUtils.toXMLStr(wmdsData);

			xmlStr = xmlStr.replaceAll(
				"<xml>", "<WBSParam>");
			xmlStr = xmlStr.replaceAll(
				"</xml>", "</WBSParam>");

			System.out.println(xmlStr);

			String result = MDUtils.invokeDNetWebService(
				END_POINT, NAME_SPACE, METHOD_NAME_WBS, SOAP_ACTION_WBS, PARAMETER_NAME, xmlStr);
			XmlData xmlData = XMLUtils.strToXMLData(result);
			Hashtable<String, ArrayList<Object>> data = xmlData.getData();
			result = getTransferValue(
				data, "Result");
			if (!"true".equals(result))
			{
				throwException(getMessage("ERROR_23") + getTransferValue(
					data, "Message"));
			}
		}
		catch (Exception e) 
		{
			throw new MESException(e, MODULE_PM, "油消耗");
		}
	}
	
	/**
	 * 获得当天状态不为新建/取消/关闭/中止/完成的工单
	 */
	public Vector<UIOrder> getActivateOrders()
	{
		OrderFilter orderFilter = getFunctions().createWorkOrderFilter();
		ServerImpl serverImpl = getFunctions().getCurrentUser().getServerImpl();
		OrderItemFilter orderItemFilter = new OrderItemFilter(serverImpl);
		orderFilter.addSearchForSubFilter(
			IWorkOrderFilterAttributes.KEY, IFilterComparisonOperators.IN,
			IWorkOrderItemFilterAttributes.ORDER_KEY, orderItemFilter);
		
//		Time currentTime = getTrxTime();
		
//		orderItemFilter.addSearchBy(IWorkOrderItemFilterAttributes.PLANNED_START_TIME,IFilterComparisonOperators.GREATER_THAN_EQUAL_TO,getDayStart(currentTime));
//		orderItemFilter.addSearchBy(IWorkOrderItemFilterAttributes.PLANNED_START_TIME,IFilterComparisonOperators.LESS_THAN_EQUAL_TO,getDayEnd(currentTime));
		
		Vector orders = getFunctions().getFilteredWorkOrders(orderFilter);
		Vector<UIOrder> uiOrders = new Vector<UIOrder>();
		for (int i = 0; i < orders.size(); i++)
		{
			Order order = (Order) orders.get(i);
			String state = order.getOrderState();
			if(IOrderState.CREATED.equals(state) || IOrderState.CANCELED.equals(state) || IOrderState.CLOSED.equals(state) || IOrderState.ABORTED.equals(state))
			{
				continue;
			}
			uiOrders.add(new UIOrder(order,getFunctions()));
		}
		return uiOrders;
	}
	
	/**
	 * 获得某产品的所有添加剂配料
	 * @param partNumber 产品代码
	 */
	public Vector<AdditivePrescription> getAdditivePrescriptions(String partNumber,String itemNumber) throws MESException
	{
		try
		{
			ATRowFilter atRowFilter = getFunctions().createATRowFilter(IATConstants.AT_TABLE_BM_ADDITIVE_PRESCRIPTION);
			atRowFilter.forColumnNameEqualTo(IATConstants.AT_COLUMN_BM_ADDITIVE_PRESCRIPTION_PART_NUMBER, partNumber);
			if(StringUtils.isNotNull(itemNumber))
				atRowFilter.forColumnNameEqualTo(IATConstants.AT_COLUMN_BM_ADDITIVE_PRESCRIPTION_ITEM_CODE, itemNumber);
			Vector atRows = getFunctions().getFilteredATRows(atRowFilter, false);
			
			Vector<AdditivePrescription> additivePrescriptions = new Vector<AdditivePrescription>();
			for (int i = 0; i < atRows.size(); i++)
			{
				additivePrescriptions.add(new AdditivePrescription((ATRow) atRows.get(i)));
			}
			return additivePrescriptions;
		}
		catch (Exception e) {
			throw new MESException(e, MODULE_PM, "添加剂配料");
		}
	}
	
	/**
	 * 取消工单
	 */
	public void  cancelOrder(UIOrder uiOrder) throws Exception
	{
		try
		{
			String orderState = uiOrder.getOrderState();
			if(IOrderState.CREATED.equals(orderState) || IOrderState.PUBLISHED.equals(orderState))
			{
				//如果是发布状态的工单需要判断是否已经领料
				if(IOrderState.PUBLISHED.equals(orderState))
				{
					LotFilter lotFilter = getFunctions().createLotFilter();
					lotFilter.forUda3EqualTo(uiOrder.getOrderName());
					int count = getFunctions().getFilteredLotCount(lotFilter);
					if(count > 0)
					{
						throwException("ERROR_24");
					}
				}
				changeOrderStatus(uiOrder, IOrderState.CANCELED);
			}
			else
			{
				throwException("ERROR_25");
			}
		}catch (Exception e) {
			throw new MESException(e, MODULE_PM, "停止投料");
		}
	}
	
	/**
	 * 获得原料拆分方法
	 */
	public Vector<MaterialSplitMethod> getMaterialSplitMethods()
	{
		ATRowFilter atRowFilter = getFunctions().createATRowFilter(IATConstants.AT_TABLE_PM_MATERIAL_SPLIT_METHOD);
		Vector atRows = getFunctions().getFilteredATRows(atRowFilter, false);
		Vector<MaterialSplitMethod> materialSplitMethods = new Vector<MaterialSplitMethod>();
		for (int i = 0; i <atRows.size(); i++)
		{
			materialSplitMethods.add(new MaterialSplitMethod((ParentATRow) atRows.get(i)));
		}
		return materialSplitMethods;
	}
	
	/**
	 * 生成一个UIOrder
	 */
	public UIOrder createUIOrder(WorkPlan workPlan)
	{
		if(workPlan != null){
			UIOrder uiOrder = createUIOrder();
			String productionLineName = workPlan.getProductionLine();
			uiOrder.setProductionLine(productionLineName);
			String sapCode = workPlan.getSapCode();
			Part part = getFunctions().getPart(sapCode);
			uiOrder.setPart(part);
			uiOrder.setPlannedQuantity(workPlan.getPlannedQty());
			Time plannedDate = DateTimeUtils.parseDateOfPnut(workPlan.getPlannedDate(), IDateFormatConstants.DATE_TIME_FORMAT_DAY);
			uiOrder.setPlannedTime(plannedDate);
			return uiOrder;
		}
		return null;
	}
	
	/**
     * 生成工单号
     * ORD+yyyyMMdd+流水号
     * @param date           日期
     * @author Nemo
     */
    public synchronized String generatorWorkOrderCode(Time date) throws Exception {
        if (date == null) {
            throwException("ERROR_26");
        }
        
        String dateString = DateTimeUtils.formatDate(date, IDateFormatConstants.DATE_TIME_FORMAT_DAY_NO_LINE);
        String planSequenceName = ORDER_PREFIX + dateString;
        int number = getSequenceNumber(planSequenceName);
        String formatNumber = format(String.valueOf(number), 3, "0");
        return planSequenceName + formatNumber;
    }
    
    /**
     * 生成批次号
     * 年（4位）＋月（2位）＋日（2位）＋产线（2位）＋序列号（2位）
     * yyyyMMdd+产线+流水号
     * @param date           日期
     * @param productionLine 产线
     * @author Nemo
     */
    public synchronized String generatorLotCode(Time date,ProductionLine productionLine) throws Exception {
        if (date == null) 
        {
            throwException("ERROR_27");
        }
        
        if (productionLine == null)
        {
        	throwException("ERROR_28");
        }
        
        String dateString = DateTimeUtils.formatDate(date, IDateFormatConstants.DATE_TIME_FORMAT_DAY_NO_LINE);

        String productionLineName = productionLine.getName();

        String planSequenceName = dateString+productionLineName;
        int number = getSequenceNumber(planSequenceName);
        return planSequenceName + format(String.valueOf(number), 2, "0");
    }


    
    /**
     * 获得该产品的所有BOM
     */
    public Vector<BillOfMaterials> getBillOfMaterials(Part part)
    {
    	String partNumber = part.getPartNumber();
    	return getBillOfMaterials(partNumber);
    }

    /**
     * 获得该产品的所有BOM
     */
	private Vector<BillOfMaterials> getBillOfMaterials(String partNumber)
	{
		BomFilter bomFilter = getFunctions().createBomFilter();
		bomFilter.forBomNameEqualTo(partNumber);
		return getFunctions().getFilteredBoms(bomFilter);
	}
	
	/**
	 * 根据产线获得所有的Route
	 */
	public Vector<UIData> getRoutes(String productionLineName)
	{
		ProductionLine productionLine = getFunctions().getProductionLineByName(productionLineName);
		return getRoutes(productionLine);
	}
	
	/**
	 * 获得所有的工序
	 */
	public Vector<UIStep> getSteps(Route route)
	{
		Vector<UIStep> result = new Vector<UIStep>();
		Vector steps = route.getSteps();
		for (int i = 0; i < steps.size(); i++)
		{
			result.add(new UIStep((Step) steps.get(i)));
		}
		return result;
	}
	
	/**
	 * 根据产线获得所有的Route
	 */
	public Vector<UIData> getRoutes(ProductionLine productionLine)
	{
		Vector<Categorical> result = new Vector<Categorical>();
		RouteFilter routeFilter = getFunctions().createRouteFilter();
		Vector routes = getFunctions().getFilteredRoutes(routeFilter);
		for (int i = 0; i < routes.size(); i++)
		{
			Route route = (Route) routes.get(i);
			Vector productionLines = route.getProductionLines();
			if(productionLines.contains(productionLine)){
				result.add(route);
				break;
			}
		}
		return convertCategoricalDataToUIData(result);
	}
	
	private static Vector<UIData> convertCategoricalDataToUIData(Vector<Categorical> datas) {
        Vector<UIData> uiDatas = new Vector<UIData>();
        for (int i = 0; i < datas.size(); i++) {
            uiDatas.add(new UIData(datas.get(i)));
        }
        return uiDatas;
    }
	
	/**
	 * 创建工单
	 * @param uiOrder	创建工单
	 */
	public UIOrder saveOrder(UIOrder uiOrder,WorkPlan workPlan) throws Exception
	{
		Response response = getFunctions().getUserTransaction();
		if (response.isError())
		{
			throw new MESException(getMessage("ERROR_29"), MODULE_PM, "创建工单");
		}
		UserTransaction userTransaction = (UserTransaction) response.getResult();
		response = userTransaction.begin();
		try
		{
			if(uiOrder == null)
			{
				throwException("ERROR_30");
			}
			
			Order order = (Order) uiOrder.getObject();
			System.out.println(order.getUDA(UDA_ORDER_SEQUENCE));
			OrderItem orderItem = (OrderItem) order.getOrderItems().firstElement();
			String productionLineName = uiOrder.getProductionLineValue();
			Integer orderSequence = uiOrder.getOrderSequence();
			Time plannedTime = orderItem.getPlannedStartTime();
			BillOfMaterials bom = uiOrder.getBom();
			
			//新建
			if(order.isNew())
			{
				if(isOrderSequenceExist(plannedTime,productionLineName,orderSequence))
				{
					throwException("ERROR_31");
				}
				else
				{
					String orderName = generatorWorkOrderCode(plannedTime);
					
					if(workPlan != null)
					{
						checkResponse(workPlan.markOrdered(orderName));
					}
					
					order.setName(orderName);
					orderItem.setName(orderName);
					checkResponse(order.save());
					createLot(order, bom);
				}
			}
			//更新
			else
			{
				if(order.isChanged())
				{
					checkResponse(order.save());
				}
				//判断RuntimeBom是否有调整
				if(bom.isChanged())
				{
					checkResponse(bom.save());
				}
			}
			response = userTransaction.commit();
			if (response.isError())
			{
				throwException("ERROR_29");
			}
			return uiOrder;
		}
		catch (Exception e)
		{
			e.printStackTrace();
			userTransaction.rollback();
			throw new MESException(e.getMessage(), MODULE_PM, "创建工单");
		}
	}
	
	/**
	 * 查询工单
	 */
	public Vector<UIOrder> searchWorkorders(String orderName,Part part,ProductionLine productionLine,String orderType,String orderState,Time plannedTimeStart,Time plannedTimeEnd) throws Exception
	{
		
		ServerImpl serverImpl = getFunctions().getCurrentUser().getServerImpl();
		OrderItemFilter orderItemFilter = new OrderItemFilter(serverImpl);
		if(part != null)
		{
			String partNumber = part.getPartNumber();
			orderItemFilter.addSearchBy(IWorkOrderItemFilterAttributes.PART_NUMBER, IFilterComparisonOperators.CONTAINING, partNumber);
		}
		if(productionLine != null)
		{
			String productionLineName = productionLine.getName();
			orderItemFilter.addSearchBy(IWorkOrderItemFilterAttributes.PLANNED_LINE, IFilterComparisonOperators.EQUAL_TO, productionLineName);
		}
		
		if(plannedTimeStart != null)
		{
			orderItemFilter.addSearchBy(IWorkOrderItemFilterAttributes.PLANNED_START_TIME,IFilterComparisonOperators.GREATER_THAN_EQUAL_TO,getDayStart(plannedTimeStart));
		}
		
		if(plannedTimeEnd != null)
		{
			orderItemFilter.addSearchBy(IWorkOrderItemFilterAttributes.PLANNED_START_TIME,IFilterComparisonOperators.LESS_THAN_EQUAL_TO,getDayEnd(plannedTimeEnd));
		}
		
		OrderFilter orderFilter = getFunctions().createWorkOrderFilter();
		orderFilter.addSearchForSubFilter(
			IWorkOrderFilterAttributes.KEY, IFilterComparisonOperators.IN,
			IWorkOrderItemFilterAttributes.ORDER_KEY, orderItemFilter);
		
		if(StringUtils.isNotNull(orderName))
		{
			orderFilter.forOrderNumberContaining(orderName);
		}
		
		if(StringUtils.isNotNull(orderType))
		{
			String orderTypeCode = OrderTypeUtil.getOrderTypeKey(orderType);
			orderFilter.forUda2EqualTo(orderTypeCode);
		}
		
		if(StringUtils.isNotNull(orderState))
		{
			orderFilter.forOrderStateEqualTo(orderState);
		}
		
		Vector orders = getFunctions().getFilteredWorkOrders(orderFilter);
		Vector<UIOrder> uiOrders = new Vector<UIOrder>();
		for (int i = 0; i < orders.size(); i++)
		{
			uiOrders.add(new UIOrder((Order) orders.get(i),getFunctions()));
		}
		return uiOrders;
	}
	
	/**
	 * 创建批次
	 */
	private Lot createLot(Order order, BillOfMaterials billOfMaterials)
		throws Exception
	{
		String orderName = order.getName();
		OrderItem orderItem = (OrderItem) order.getOrderItems().firstElement();
		Lot lot = getFunctions().createLot(
                orderName, order);
		lot.setOrderItem(orderName);
		lot.setRouteName(orderItem.getPlannedRoute());
		lot.setBulk();
		lot.setQuantity(orderItem.getPreciseQuantityOrdered());
		Response response = lot.save();
		if (response.isError())
		{
			throw new Exception(getMessage("ERROR_32") + response.getFirstErrorMessage());
		}

		if (billOfMaterials != null)
		{
			billOfMaterials = regroupBom(billOfMaterials);
			response = lot.applyRuntimeBom(billOfMaterials);
			if (response.isError())
			{
				throw new Exception(getMessage("ERROR_33") + response.getFirstErrorMessage());
			}
		}

		return lot;
	}

	/**
	 * 重组BOM，将替代料配置到Bom上面
	 */
	private BillOfMaterials regroupBom(BillOfMaterials billOfMaterials) throws Exception
	{
		Vector bomItems = billOfMaterials.getBomItems();
		for (int i = 0; i < bomItems.size(); i++)
		{
			BomItem bomItem = (BomItem) bomItems.get(i);
			AlternateBomItem[] alternateBomItems = bomItem.getAlternateBomItems();
			for (int j = 0; j < alternateBomItems.length; j++)
			{
				Part part = alternateBomItems[j].getPart();
				BomItem bomItemNew = billOfMaterials.addBomItem(part);
				bomItemNew.setDescription(part.getDescription());
				bomItemNew.setPreciseQuantity(bomItem.getPreciseQuantity());
				bomItemNew.setDecimalScale(bomItem.getDecimalScale());
				bomItemNew.setUDA(
					bomItem.getUDA(1), 1);
				bomItemNew.setUDA(
					bomItem.getUDA(IUDADefinitions.UDA_BOM_ITEM_CONFIRM_TIME),
					IUDADefinitions.UDA_BOM_ITEM_CONFIRM_TIME);
				bomItemNew.setCategory(String.valueOf(bomItem.getKey()));
				bomItem.removeAlternateBomItem(alternateBomItems[j]);
			}
		}
		return billOfMaterials;
	}

	/**
	 * 查看当前工单生产顺序是否已经被使用
	 * @param plannedTime			计划日期
	 * @param productionLineName	产线
	 * @param orderSequence			生产序号
	 */
	private boolean isOrderSequenceExist(Time plannedTime, String productionLineName,
		Integer orderSequence)
	{
		ServerImpl serverImpl = getFunctions().getCurrentUser().getServerImpl();
		OrderItemFilter orderItemFilter = new OrderItemFilter(serverImpl);
		
		orderItemFilter.addSearchBy(IWorkOrderItemFilterAttributes.PLANNED_LINE, IFilterComparisonOperators.EQUAL_TO, productionLineName);
		orderItemFilter.addSearchBy(IWorkOrderItemFilterAttributes.PLANNED_START_TIME,IFilterComparisonOperators.GREATER_THAN_EQUAL_TO,getDayStart(plannedTime));
		orderItemFilter.addSearchBy(IWorkOrderItemFilterAttributes.PLANNED_START_TIME,IFilterComparisonOperators.LESS_THAN_EQUAL_TO,getDayEnd(plannedTime));
		
		OrderFilter orderFilter = getFunctions().createWorkOrderFilter();
		orderFilter.addSearchForSubFilter(
			IWorkOrderFilterAttributes.KEY, IFilterComparisonOperators.IN,
			IWorkOrderItemFilterAttributes.ORDER_KEY, orderItemFilter);
		
		orderFilter.forUda1EqualTo(String.valueOf(orderSequence));
		
		int count = getFunctions().getFilteredWorkOrderCount(orderFilter);
		return count>0;
	}
	
	/**
	 * 判断当前工单是否已经在当前工序上启动
	 */
	public boolean isOrderStarted() throws Exception
	{
		try
		{
			UIOrder uiOrder = getCurrentUIOrder();
			Lot lot = uiOrder.getLot();
			return isLotStarted(lot);
		}
		catch (Exception e) 
		{
			throw new MESException(e,MODULE_PM,"工单启动");
		}
	}
	
	/**
	 * 判断当前批次是否已经在当前工序上启动
	 */
	public boolean isLotStarted(Lot lot) throws Exception
	{
		try
		{
			if(lot.getLotType() == Lot.FLOW)
			{
				lot = getCurrentStepPartialLot(lot, getCurrentStep());
				if(lot == null)
				{
					return false;
				}
			}
			String status = lot.getCurrentStatus();
			// 若已经启动
			if (ITrackedObjectConstants.STATUS_STR_STARTED.equals(status))
			{
				// 判断在当前工序上启动
				Step step = lot.getPresentRouteStep();
				DeAnzaForm stepForm = step.getForm();
				if (stepForm == null)
				{
					throwException("ERROR_34");
				}
				Form currentForm = getFunctions().getActiveDsForm();
				return stepForm.getName().equals(
					currentForm.getName());
			}
			else
			{
				return false;
			}
		}
		catch (Exception e)
		{
			throw new MESException(e, MODULE_PM, "工单启动");
		}
	}
	
	/**
	 * 获得当前工序上的Lot
	 */
	public Vector<Lot> getCurrentLots() throws MESException
	{
		try
		{
			UIOrder uiOrder = getCurrentUIOrder();
			uiOrder.refresh();
			Step step = getCurrentStep();
			if(step == null)
			{
				return null;
			}
			Vector<Lot> lots = uiOrder.getLots();
			Vector<Lot> removedLots = new Vector<Lot>();
			for (int i = 0; i < lots.size(); i++)
			{
				Lot lot = lots.get(i);
				Vector<LotHistory> lotHistorys = lot.getLotHistory();
				for (int j = 0; j < lotHistorys.size(); j++)
				{
					LotHistory lotHistory = lotHistorys.get(j);
					Time completeTime = lotHistory.getCompletedTime();
					if(completeTime == null)
						continue;
					String operationName = lotHistory.getOperationName();
					if(operationName.equals(step.getOperationName()))
					{
						removedLots.add(lot);
					}
				}
			}
			
			for (int i = 0; i < removedLots.size(); i++)
			{
				Lot lot = removedLots.get(i);
				lots.remove(lot);
			}
			return lots;
		}
		catch (Exception e)
		{
			e.printStackTrace();
			throw new MESException(e, MODULE_PM, "获得批次");
		}

	}
	
	/**
	 * 将工单从当前工序上启动
	 */
	public void startOrderInCurrentStep() throws Exception
	{
		try{
			UIOrder uiOrder = getCurrentUIOrder();
			Lot lot = uiOrder.getLot();
			startLotInCurrentStep(lot);
			if(!uiOrder.getOrderState().equals(IOrderState.STARTED))
			{
				changeOrderStatus(uiOrder, IOrderState.STARTED);
				Order order = uiOrder.getObject();
				order.setUDT(getTrxTime(), 1);
				order.save();
			}
		}
		catch (Exception e) 
		{
			throw new MESException(e,MODULE_PM,"工单启动");
		}
	}
	
	/**
	 * 将批次从当前工序上启动
	 */
	public void startLotInCurrentStep_(Lot lot) throws Exception
	{
		try{
			Queue queue = lot.getQueue();
			//若Queue为空，则表示当前批次仍然在上一工序上制造
			Step step = lot.getPresentRouteStep();
			Step nextStep = null;
			if(queue == null)
			{
				//获得当前正在制造的工序的下一步工序
				nextStep = getNextStep(step,lot);
			}
			//否则判断该批次是否在当前工序前的Queue上
			else
			{
				nextStep = getNextStep(queue, lot);
			}
			
			//若无法获得，则抛出异常
			if(nextStep == null)
			{
				throwException("ERROR_35");
			}
			//判断下一步工序是否为当前工序
			else
			{
				DeAnzaForm nextForm = nextStep.getForm();
				if(nextForm == null)
				{
					throwException("ERROR_36");
				}
				Form dsForm = getFunctions().getActiveDsForm();
				//下一工步就是当前工步
				if(nextForm.getName().equals(dsForm.getName()))
				{
					//判断工单是否第一次启动
					Order order = lot.getOrder();
					String status = order.getCurrentStatus();
					if(ITrackedObjectConstants.STATUS_STR_CREATED.equals(status))
					{
						String stepName = order.getUDA(3);
						if(!nextStep.getName().equals(stepName))
						{
							throw new Exception(getMessage("ERROR_37")+stepName);
						}
					}
					
					WorkCenter workCenter = getCurrentWorkCenter(nextStep);
 					//在当前工步上启动
					Response response = lot.startAtStepAtWorkCenter(getTrxTime(),nextStep.getName(), workCenter.getName(),getFunctions().getCurrentUser().getLastName());
					if(response.isError())
					{
						throw new Exception(getMessage("ERROR_38")+nextStep.getOperation().getDescription()+getMessage("ERROR_39")+response.getFirstErrorMessage());
					}
				}
				else
				{
					throwException("ERROR_40");
				}
			}
		}
		catch (Exception e) 
		{
			e.printStackTrace();
			throw new MESException(e,MODULE_PM,"工单启动");
		}
	}
	
	/**
	 * 将批次从当前工序上启动
	 */
	public void startLotInCurrentStep(Lot lot) throws Exception
	{
		try{
			lot.refresh();
			//当前工序
			Step step = getCurrentStep();
			int lotType = lot.getLotType();
			//流水线
			if(lotType == Lot.FLOW)
			{
				Lot partialLot = getPartialLotInCurrentStep(lot,step);
				BigDecimal qty = partialLot.getPreciseQuantity();
				WorkCenter workCenter = getCurrentWorkCenter(step);
				Response response = partialLot.startAtStepAtWorkCenter(getTrxTime(), qty.divide(new BigDecimal(2),3), step.getName(), workCenter.getName(), null, false);
				if(response.isError())
				{
					throw new Exception(getMessage("ERROR_38")+step.getOperation().getDescription()+getMessage("ERROR_39")+response.getFirstErrorMessage());
				}
			}
			//非流水线
			else if(lotType == Lot.BULK)
			{
				//判断是否已经在前一个工序启动
				Step presentRouteStep = lot.getPresentRouteStep();
				WorkCenter workCenter = getCurrentWorkCenter(step);
				
				//若正在制造,则需要拆分为PartialLot
				if(presentRouteStep != null)
				{
					Step nextStep = getNextStep(presentRouteStep, lot);
					//若无法获得，则抛出异常
					if(nextStep == null)
					{
						throwException("ERROR_35");
					}
					else
					{
						//若下一步工序为当前工序
						if(nextStep.getName().equals(step.getName()))
						{
							BigDecimal qty = lot.getPreciseQuantity();
							Response response = lot.startAtStepAtWorkCenter(getTrxTime(), qty.divide(new BigDecimal(2)), step.getName(), workCenter.getName(), null, false);
							if(response.isError())
							{
								throw new Exception(getMessage("ERROR_38")+step.getOperation().getDescription()+getMessage("ERROR_39")+response.getFirstErrorMessage());
							}
						}
						else
						{
							throwException("ERROR_40");
						}
					}
				}
				//否则在Queue上
				else
				{
					Step nextStep = getNextStep(lot.getQueue(), lot);
					//若无法获得，则抛出异常
					if(nextStep == null)
					{
						throwException("ERROR_35");
					}
					else
					{
						//若下一步工序为当前工序
						if(nextStep.getName().equals(step.getName()))
						{
							
							//判断工单是否第一次启动
							Order order = lot.getOrder();
							String status = order.getCurrentStatus();
							if(ITrackedObjectConstants.STATUS_STR_CREATED.equals(status))
							{
								String stepName = order.getUDA(3);
								if(!step.getName().equals(stepName))
								{
									throw new Exception(getMessage("ERROR_37")+stepName);
								}
							}
							
							Response response = lot.startAtStepAtWorkCenter(getTrxTime(),nextStep.getName(), workCenter.getName(),getFunctions().getCurrentUser().getLastName());
							if(response.isError())
							{
								throw new Exception(getMessage("ERROR_38")+step.getOperation().getDescription()+getMessage("ERROR_39")+response.getFirstErrorMessage());
							}
						}
						else
						{
							throwException("ERROR_40");
						}
					}
				}
			}
		}
		catch (Exception e) 
		{
			e.printStackTrace();
			throw new MESException(e,MODULE_PM,"工单启动");
		}
	}
	
	/**
	 * 获得所有下一步的流水工序
	 */
	private Vector<Step> getAllPartialSteps(Step step)
	{
		Vector<Step> steps = new Vector<Step>();
		steps.add(step);
		Vector<Step> nextSteps = step.getNextSteps();
		if(nextSteps != null && nextSteps.size() == 1)
		{
			Step nextStep = nextSteps.firstElement();
			if(nextStep.getValueAdded())
			{
				steps.addAll(getAllPartialSteps(nextStep));
			}
		}
		return steps;
	}

	/**
	 * 根据FLowlot获得当前工步的PartialLot
	 */
	private Lot getPartialLotInCurrentStep(Lot lot, Step step) throws Exception
	{
		Lot startLot = null;
		
		if(lot != null)
		{
			Vector<Lot> lots = step.getLots();
			for (int i = 0; i < lots.size(); i++)
			{
				Lot stepLot = lots.get(i);
				if (stepLot.getName().equals(
					lot.getName()) && (stepLot.getLotType() == Lot.PARTIAL))
				{
					throw new Exception("批次已经在当前工步上开始");
				}
			}
		}
		
		if(startLot == null)
		{
			Step perviousStep = (Step) step.getPreviousSteps().firstElement();
			Vector<Lot> lots = perviousStep.getLots();
			for (int i = 0; i < lots.size(); i++)
			{
				Lot stepLot = lots.get(i);
				if (stepLot.getName().equals(
					lot.getName()) && (stepLot.getLotType() == Lot.PARTIAL))
				{
					startLot = stepLot;
					break;
				}
			}
		}
		
		if(startLot == null)
		{
			Queue queue = step.getIncomingQueues().firstElement();
			Vector<Lot> lots = queue.getLots();
			for (int i = 0; i < lots.size(); i++)
			{
				Lot stepLot = lots.get(i);
				if (stepLot.getName().equals(
					lot.getName()) && (stepLot.getLotType() == Lot.PARTIAL))
				{
					startLot = stepLot;
					break;
				}
			}
		}
		
		
		if(startLot == null)
		{
			throw new Exception("该批次还未在上一个工步上开始");
		}
		
		return startLot;
	}

	/**
	 * 获得产品的下一个工序
	 */
	private Step getNextStep(Step step, Lot lot)
	{
		String productionLineName = lot.getProductionLineName();
		ProductionLine productionLine = getFunctions().getProductionLineByName(productionLineName);
		Vector workCenters = productionLine.getWorkCenters();
		Vector nextSteps = step.getNextSteps();
		for (int i = 0; i < nextSteps.size(); i++)
		{
			Step nextStep = (Step) nextSteps.get(i);
			Vector stepWorkCenters = nextStep.getWorkCenters();
			for (int j = 0; j < stepWorkCenters.size(); j++)
			{
				WorkCenter stepWorkCenter = (WorkCenter) stepWorkCenters.get(j);
				if(workCenters.contains(stepWorkCenter))
				{
					return nextStep;
				}
			}
		}
		return null;
	}
	
	/**
	 * 获得产品的下一个工序
	 */
	private Step getNextStep(Queue queue, Lot lot)
	{
		String productionLineName = lot.getProductionLineName();
		ProductionLine productionLine = getFunctions().getProductionLineByName(productionLineName);
		Vector workCenters = productionLine.getWorkCenters();
		Vector nextSteps = queue.getSteps();
		for (int i = 0; i < nextSteps.size(); i++)
		{
			Step nextStep = (Step) nextSteps.get(i);
			Vector stepWorkCenters = nextStep.getWorkCenters();
			for (int j = 0; j < stepWorkCenters.size(); j++)
			{
				WorkCenter stepWorkCenter = (WorkCenter) stepWorkCenters.get(j);
				if(workCenters.contains(stepWorkCenter))
				{
					return nextStep;
				}
			}
		}
		return null;
	}
	
	/**
	 * 将工单从当前工序上完成
	 */
	public void completeOrderInCurrentStep() throws MESException
	{
		try{
			UIOrder uiOrder = getCurrentUIOrder();
			Lot lot = uiOrder.getLot();
			completeLotInCurrentStep(lot);
		}
		catch (Exception e) 
		{
			throw new MESException(e,MODULE_PM,"工单启动");
		}
	}
	
	/**
	 * 检查当前批次是否已经在当前工步上开始
	 */
	public boolean isLotStartInCurrentStep(Lot lot) throws Exception
	{
		try
		{
			if (lot.getLotType() == Lot.FLOW)
			{
				lot = getCurrentStepPartialLot(lot, getCurrentStep());
			}
			Step step = lot.getPresentRouteStep();

			Step CurrentStep = getCurrentStep();
			if (step == null)
			{
				return false;
			}
			else
			{
				return (step.getKey() == CurrentStep.getKey());
			}
		}
		catch (Exception e)
		{
			throw new MESException(e, MODULE_PM, "批次状态检查");
		}
	}
	
	/**
	 * 将该批次在当前工序上完成
	 */
	public void completeLotInCurrentStep(Lot lot) throws MESException
	{
		try
		{
			lot.refresh();
			Step currentStep = getCurrentStep();
			if (lot.getLotType() == Lot.FLOW)
			{
				// 获得当前工步上的PartialLot
				lot = getCurrentStepPartialLot(
					lot, currentStep);
				if (lot == null)
				{
					throw new Exception("该批次还未在当前工序上开始");
				}
				else
				{
					//检查是否在上一工步存在该批次，若存在，则不允许在当前批次完成
					Step perviousStep = (Step) currentStep.getPreviousSteps().firstElement();
					if(isPartialLotInPerviousStep(lot.getName(),perviousStep))
					{
						throw new Exception("该批次还未在上一工序完成");
					}
					
					WorkCenter workCenter = getCurrentWorkCenter(currentStep);
					Response response = lot.completeAtStepAtWorkCenter(
						getTrxTime(), currentStep.getName(), workCenter.getName(),
						COMPLETE_REASON_NORMAL, getFunctions().getCurrentUser().getLastName());
					if (response.isError())
					{
						throwException(getMessage("ERROR_44")
							+ currentStep.getOperation().getDescription() + getMessage("ERROR_45")
							+ response.getFirstErrorMessage());
					}
				}
			}
			else
			{
				Step step = lot.getPresentRouteStep();
				if (step == null)
				{
					throwException("ERROR_41");
				}
				else
				{
					if (currentStep.getKey() != step.getKey())
					{
						throw new Exception(getMessage("ERROR_42")
							+ step.getOperation().getDescription() + getMessage("ERROR_43"));
					}
					WorkCenter workCenter = getCurrentWorkCenter(lot);
					Response response = lot.completeAtStepAtWorkCenter(
						getTrxTime(), step.getName(), workCenter.getName(), COMPLETE_REASON_NORMAL,
						getFunctions().getCurrentUser().getLastName());
					if (response.isError())
					{
						throwException(getMessage("ERROR_44")
							+ step.getOperation().getDescription() + getMessage("ERROR_45")
							+ response.getFirstErrorMessage());
					}
				}
			}
		}
		catch (Exception e)
		{
			throw new MESException(e, MODULE_PM, "工单启动");
		}
	}

	/**
	 * 检查是否在上一工步存在该批次，若存在，则不允许在当前批次完成
	 * @param name			批次名称
	 * @param perviousStep	上一工步
	 */
	private boolean isPartialLotInPerviousStep(String name, Step perviousStep)
	{
		Vector<Lot> lots = perviousStep.getLots();
		for (int i = 0; i < lots.size(); i++)
		{
			if(name.equals(lots.get(i).getName()))
			{
				return true;
			}
		}
		return false;
	}

	/**
	 * 根据FlowLot和当前工步获得PartialLot
	 */
	private Lot getCurrentStepPartialLot(Lot lot, Step currentStep) throws Exception
	{
		if(lot.getLotType() == Lot.FLOW)
		{
			Vector<Lot> partialLots = lot.getPartialLots();
			for (int i = 0; i < partialLots.size(); i++)
			{
				Lot partialLot = partialLots.get(i);
				Step routeStep = partialLot.getPresentRouteStep();
				if(routeStep != null)
				{
					if(routeStep.getKey() == currentStep.getKey())
					{
						return partialLot;
					}
				}
			}
			return null;
		}
		else
		{
			throw new Exception("批次类型必须为Flow Lot");
		}
	}

	/**
	 * 设置当前工单
	 */
	public void setCurrentUIOrder(UIOrder uiOrder)
	{
		getFunctions().setProperty("uiOrder",uiOrder);
	}
	
	/**
	 * 获得当前工单
	 */
	public UIOrder getCurrentUIOrder()
	{
		return (UIOrder) getFunctions().getProperty("uiOrder");
	}
	
	/**
	 * 获得一个工单
	 * @param orderNumber 工单号
	 */
	public UIOrder getUIOrder(String orderNumber)
	{
		Order order = getFunctions().getWorkOrder(orderNumber);
		return new UIOrder(order, getFunctions());
	}
	
	/**
	 * 打印退库条码
	 * @param partNumber	物料代码
	 * @param quantity		数量
	 */
	public Lot printShipLotBarcode(Order order ,Part part,BigDecimal quantity) throws Exception
	{
		Response response = getFunctions().getUserTransaction();
		if (response.isError())
		{
			throw new MESException(getMessage("ERROR_29"), MODULE_PM, "物料退库");
		}
		UserTransaction userTransaction = (UserTransaction) response.getResult();
		response = userTransaction.begin();
		if (response.isError())
		{
			throw new MESException(getMessage("ERROR_29"), MODULE_PM, "物料退库");
		}
		try
		{
			if(part == null)
			{
				throwException("ERROR_46");
			}
			
			if(quantity == null || quantity.equals(BigDecimal.ZERO))
			{
				throwException("ERROR_47");
			}
			
			//获得该工单该批次的信息
			String orderName = order.getOrderNumber();
			String partNumber = part.getPartNumber();
			LotFilter lotFilter = getFunctions().createLotFilter();
			lotFilter.forUda3EqualTo(orderName);
			lotFilter.forPartNumberEqualTo(partNumber);
			lotFilter.addOrderBy(ILotFilterAttributes.CREATIONTIME, IFilterSortOrders.DESCENDING);
			Vector lots = getFunctions().getFilteredLots(lotFilter);
			if(lots == null || lots.size() == 0)
			{
				throwException("ERROR_48");
			}
			
			Lot lot = (Lot) lots.firstElement();
			String supplier = lot.getUDA(UDA_LOT_SUPPLIER);
			String supplierLotNo = lot.getUDA(UDA_LOT_SUPPLIER_LOTNO);
			
			UIOrder uiOrder = getUIOrder(orderName);
			String productionLineName = uiOrder.getProductionLineValue();
			
			//获得条码
			PrintComponent printComponent = new PrintComponent(getFunctions());
			String barcode = printComponent.getBarcodeFromWMS(part, supplier, supplierLotNo, orderName, productionLineName, null, quantity.toString(),3);
			if(StringUtils.isNull(barcode))
			{
				throwException("ERROR_49");
			}
			
			response = getFunctions().receiveBulkLot(barcode, quantity, part, false, null, null);
			if(response.isError())
			{
				throw new Exception(getMessage("ERROR_50")+response.getFirstErrorMessage());
				
			}
			Lot newlot = (Lot) response.getResult();
			newlot.setUDA(supplier, UDA_LOT_SUPPLIER);
			newlot.setUDA(supplierLotNo, UDA_LOT_SUPPLIER_LOTNO);
			response = newlot.save();
			if(response.isError())
			{
				throw new Exception(getMessage("ERROR_50")+response.getFirstErrorMessage());
			}
			newlot.refresh();
			
			barcode = generateMaterialBarcode(barcode, newlot);
			printComponent.printBarCode(barcode, IPrintConstants.BARCODE_TYPE_MATERIAL);
			PrintComponent.logPrintRecord(getFunctions(), barcode,IPrintConstants.BARCODE_TYPE_MATERIAL,orderName,productionLineName,part.getDescription());
			
			response = userTransaction.commit();
			if (response.isError())
			{
				throwException("ERROR_29");
			}

			return newlot;
		}
		catch (Exception e)
		{
			userTransaction.rollback();
			throw new MESException(e, MODULE_PM, "物料退库");
		}
	}
	
	/**
	 * 保存并打印解冻架条码
	 */
	public Lot printMaterialBarcode(Vector<Lot> lots,Carrier carrier,String location,String quantityStr) throws MESException
	{
		Response response = getFunctions().getUserTransaction();
		if (response.isError())
		{
			throw new MESException(getMessage("ERROR_29"), MODULE_PM, "保存并打印解冻架条码");
		}
		UserTransaction userTransaction = (UserTransaction) response.getResult();
		response = userTransaction.begin();
		if (response.isError())
		{
			throw new MESException(getMessage("ERROR_29"), MODULE_PM, "保存并打印解冻架条码");
		}
		try
		{
			//检验Lot是否属于同一个供应商、批次、工单号
			validateMaterials(lots);
			
			//数量
			BigDecimal quantity = new BigDecimal(quantityStr);
			
			//启动工单
			if(!isOrderStarted())
			{
				startOrderInCurrentStep();
			}
			
			//保存坐标和数量
			carrier.setUDA(location, UDA_CARRIER_LOCATION);
			response = carrier.save();
			if (response.isError())
			{
				throwException("ERROR_51");
			}
			
			String[] locations = location.split("\\,");
			Integer x = Integer.valueOf(locations[0]);
			Integer y = Integer.valueOf(locations[1]);
			
			ATRowFilter atRowFilter = getFunctions().createATRowFilter(AT_TABLE_PM_LOCATION);
			atRowFilter.forColumnNameEqualTo(AT_COLUMN_PM_LOCATION_X_LOCATION, x);
			atRowFilter.forColumnNameEqualTo(AT_COLUMN_PM_LOCATION_Y_LOCATION, y);
			Vector atRows = getFunctions().getFilteredATRows(atRowFilter, false);
			ATRow atRow = null;
			if(atRows != null && atRows.size() == 1)
			{
				atRow = (ATRow) atRows.firstElement();
			}
			else
			{
				ATDefinition atLocation = getFunctions().getATDefinition(AT_TABLE_PM_LOCATION);
				response = atLocation.createATRow();
				if(response.isError())
				{
					throwException("ERROR_52");
				}
				else
				{
					atRow = (ATRow) response.getResult();
				}
			}
			
			atRow.setValue(AT_COLUMN_PM_LOCATION_X_LOCATION, x);
			atRow.setValue(AT_COLUMN_PM_LOCATION_Y_LOCATION, y);
			atRow.setValue(AT_COLUMN_PM_LOCATION_CARRIER_NAME, carrier.getName());
			checkResponse(atRow.save(getTrxTime(), null, null));
			
			//取得一些基本信息
			Lot lot = lots.firstElement();
			String supplier = lot.getUDA(UDA_LOT_SUPPLIER);
			String supplierLotNo = lot.getUDA(UDA_LOT_SUPPLIER_LOTNO);
			Part part = lot.getPart();
			Time outTime = lot.getUDT(UDT_LOT_OUT_TIME);
			
			UIOrder uiOrder = getCurrentUIOrder();
			String orderNumber = uiOrder.getOrderName();
			
			//获得条码
			PrintComponent printComponent = new PrintComponent(getFunctions());
			String barcode = printComponent.generateTestBarcode("JDJ");
			if(StringUtils.isNull(barcode))
			{
				throwException("ERROR_53");
			}
			
			response = getFunctions().receiveBulkLot(barcode, BigDecimal.ZERO, part, false, null, carrier);
			if(response.isError())
			{
				throwException("ERROR_54");
			}
			Lot newlot = (Lot) response.getResult();
			
			StringBuffer lotsName = new StringBuffer();
			
			newlot.changeToWIP();
			
			//保存解冻后温度
			for (int i = 0; i < lots.size(); i++)
			{
				Lot lotMaterial = lots.get(i);
				checkResponse(lotMaterial.save());
				
				BigDecimal lotMaterialQuantity = lotMaterial.getPreciseQuantity();
				BigDecimal consumedQty = BigDecimal.ZERO;
				Boolean isClose = false;
				//消耗还有剩余
				if(quantity.compareTo(BigDecimal.ZERO) > 0)
				{
					//消耗量大于物料量
					if(quantity.compareTo(lotMaterialQuantity) > -1)
					{
						consumedQty = lotMaterialQuantity;
						isClose = true;
					}
					//消耗量小于物料量
					else
					{
						consumedQty = quantity;
					}
					//消耗物料
					BigDecimal mainQty = lotMaterialQuantity.subtract(consumedQty);
					checkResponse(lotMaterial.changeBulkLotQuantity(getTrxTime(), mainQty, null, null));
					if(isClose)
						checkResponse(lotMaterial.close("Consumed"));
					//扣减消耗数量
					quantity = quantity.subtract(consumedQty);
					//记录托盘条码
					if(i != 0)
						lotsName.append(",");
					lotsName.append(lotMaterial.getName());
				}
			}
			
			if(quantity.compareTo(BigDecimal.ZERO) > 0)
			{
				throwException("ERROR_55");
			}
	
			newlot.setUDA(supplier, UDA_LOT_SUPPLIER);
			newlot.setUDA(supplierLotNo, UDA_LOT_SUPPLIER_LOTNO);
			newlot.setUDA(orderNumber, UDA_LOT_ORDER_NUMBER);
			newlot.setUDA(lotsName.toString(), UDA_LOT_MEGRE_CODE);
			newlot.setUDT(outTime, UDT_LOT_OUT_TIME);
			newlot.setDescription(part.getDescription());
			checkResponse(newlot.save());
			
			//调整数量
			checkResponse(newlot.changeBulkLotQuantity(getTrxTime(), new BigDecimal(quantityStr), null, "解冻架打印批次修改数量"));
			
			//添加到解冻架
//			checkResponse(carrier.addLot(newlot));
			
			carrier.setUDA(orderNumber, UDA_CARRIER_ORDER_NUMBER);
			checkResponse(carrier.save());
			
			barcode = generateMaterialBarcode(barcode,newlot);
			printComponent.printBarCode(barcode, IPrintConstants.BARCODE_TYPE_MATERIAL);
			PrintComponent.logPrintRecord(getFunctions(), barcode,IPrintConstants.BARCODE_TYPE_MATERIAL,orderNumber,uiOrder.getProductionLineValue(),part.getDescription());
			
			checkResponse(userTransaction.commit());
			return newlot;
		}
		catch (Exception e)
		{
			e.printStackTrace();
			userTransaction.rollback();
			throw new MESException(getMessage("ERROR_56"), MODULE_PM, "保存/打印解冻架条码");
		}
	}

	/**
	 * 组成物料条码
	 * @param barcode	流水号
	 * @param lot		物料
	 */
	private String generateMaterialBarcode(String barcode, Lot lot)
	{
		Time time = lot.getCreationTime();
		Part part = lot.getPart();
		String partName = part.getDescription();
		String timeStr = DateTimeUtils.formatDate(time, "yyyy-MM-dd");
		String supplier = lot.getUDA(UDA_LOT_SUPPLIER);
		String supplierLotNo = lot.getUDA(UDA_LOT_SUPPLIER_LOTNO);
		String userName = getFunctions().getCurrentUser().getName();
		return barcode+","+partName+","+timeStr+","+userName+","+supplier+","+supplierLotNo;
	}

	/**
	 * 检验原料是否属于同一个供应商、批次、工单号
	 */
	private void validateMaterials(Vector<Lot> lots) throws Exception
	{
		String supplier = null;
		String supplierLot = null;
		String orderNumber = null;
		if(lots != null && lots.size() > 0)
		{
			for (int i = 0; i < lots.size(); i++)
			{
				Lot lot = lots.get(i);
				String lotSupplier = lot.getUDA(UDA_LOT_SUPPLIER);
				String lotSupplierLot = lot.getUDA(UDA_LOT_SUPPLIER_LOTNO);
				String lotOrderNumber = lot.getUDA(UDA_LOT_ORDER_NUMBER);
				
				if(StringUtils.isNull(lotSupplier))
				{
					throw new Exception(getMessage("ERROR_57")+lot.getName()+getMessage("ERROR_58"));
				}
				
				if(StringUtils.isNull(lotSupplierLot))
				{
					throw new Exception(getMessage("ERROR_57")+lot.getName()+getMessage("ERROR_59"));
				}
				
				if(StringUtils.isNull(lotOrderNumber))
				{
					throw new Exception(getMessage("ERROR_57")+lot.getName()+getMessage("ERROR_60"));
				}
				
				if(supplier == null)
				{
					supplier = lotSupplier;
				}
				if(supplierLot == null)
				{
					supplierLot = lotSupplierLot;
				}
				if(orderNumber == null)
				{
					orderNumber = lotOrderNumber;
				}
				
				if(lotSupplier.equals(supplier) && lotSupplierLot.equals(supplierLot) && lotOrderNumber.equals(orderNumber))
				{
					continue;
				}
				else
				{
					throw new Exception(getMessage("ERROR_57")+lot.getName()+getMessage("ERROR_61"));
				}
			}
		}
		else
		{
			throwException("ERROR_62");
		}
		
	}

	/**
	 * 获得当前工步
	 */
	public Step getCurrentStep() throws MESException
	{
		try
		{
			UIOrder uiOrder = getCurrentUIOrder();
			if (uiOrder == null)
			{
				throwException("ERROR_63");
			}
			Lot lot = uiOrder.getLot();
			if(lot != null)
			{
				Route route = lot.getRoute();
				Vector steps = route.getSteps();
				Form currentForm = getFunctions().getActiveDsForm();
				String formName = currentForm.getName();
				for (int i = 0; i < steps.size(); i++)
				{
					Step step = (Step) steps.get(i);
					DeAnzaForm form = step.getForm();
					if(form != null && formName.equals(form.getName()))
					{
						return step;
					}
				}
			}
			return null;
		}
		catch (Exception e)
		{
			throw new MESException(e, MODULE_PM, "获得当前工步");
		}
	}
	
	/**
	 * 获得当前的DCS
	 * @param dcsType	DCS类型
	 */
	private HashMap<String,DataCollectionSet> getCurrentDCS(String dcsType) throws Exception
	{
		Step step = getCurrentStep();
		if(step == null)
		{
			throwException("ERROR_64");
		}
		HashMap<String,DataCollectionSet> datas = new HashMap<String,DataCollectionSet>();
		Vector dataCollections = step.getDataCollections();
		for (int i = 0; i < dataCollections.size(); i++)
		{
			DataCollectionSet dataCollection = (DataCollectionSet) dataCollections.get(i);
			String category = dataCollection.getCategory();
			if(dcsType.equals(category))
			{
				datas.put(dataCollection.getName(),dataCollection);
			}
		}
		return datas;
	}
	
	/**
	 * 获得当前所有的DCS
	 */
	private HashMap<String,DataCollectionSet> getAllDCS() throws Exception
	{
		Step step = getCurrentStep();
		if(step == null)
		{
			throwException("ERROR_64");
		}
		HashMap<String,DataCollectionSet> datas = new HashMap<String,DataCollectionSet>();
		Vector dataCollections = step.getDataCollections();
		for (int i = 0; i < dataCollections.size(); i++)
		{
			DataCollectionSet dataCollection = (DataCollectionSet) dataCollections.get(i);
			datas.put(dataCollection.getName(),dataCollection);
		}
		return datas;
	}
	
	/**
	 * 添加一条手动采集数据
	 * @param key		采集项
	 * @param value		采集值
	 */
	public void addManualDCSValue(Lot lot,String dcsName,String key,Object value) throws MESException
	{
		try{
			HashMap<String,DataCollectionSet> dataCollectionSets = getAllDCS();
			if(dataCollectionSets.size() == 0)
			{
				throwException("ERROR_65");
			}
			DataCollectionSet dcs = dataCollectionSets.get(dcsName);
			if(dcs == null)
			{
				throw new Exception(getMessage("ERROR_66")+dcsName);
			}
			addDCSValue(dcs, lot, key, value);
		}catch (Exception e) {
			throw new MESException(e, MODULE_PM, "手动采集工艺参数");
		}
	}
	
	/**
	 * 添加一条手动采集数据
	 */
	public void addManualDCSValue(Lot lot,String dcsName,HashMap<String, Object> data) throws MESException
	{
		try{
			HashMap<String,DataCollectionSet> dataCollectionSets = getAllDCS();
			if(dataCollectionSets.size() == 0)
			{
				throwException("ERROR_65");
			}
			DataCollectionSet dcs = dataCollectionSets.get(dcsName);
			if(dcs == null)
			{
				throw new Exception(getMessage("ERROR_66")+dcsName);
			}
			addDCSValue(dcs, lot, data);
		}catch (Exception e) {
			throw new MESException(e, MODULE_PM, "手动采集工艺参数");
		}
	}
	
	/**
	 * 添加一条采集数据的一个采集项
	 * @param dcs		工艺参数集
	 * @param Lot		物料/批次
	 * @param key		采集项
	 * @param value		采集值
	 */
	public void addDCSValue(DataCollectionSet dcs,Lot lot,String key,Object value) throws Exception
	{
		try
		{
			HashMap<String, Object> data = new HashMap<String, Object>();
			data.put(
				key, value);
			addDCSValue(
				dcs, lot, data);
		}
		catch (Exception e)
		{
			throw new MESException(e, MODULE_QM, "数据采集");
		}
	}
	
	/**
	 * 添加一条采集数据多个采集项
	 * @param dcs		工艺参数集
	 * @param Lot		物料/批次
	 * @param key		采集项
	 * @param value		采集值
	 */
	public void addDCSValue(DataCollectionSet dcs,Lot lot,HashMap<String, Object> data) throws Exception
	{
		try
		{
			ArrayList<HashMap<String, Object>> datas = new ArrayList<HashMap<String, Object>>();
			datas.add(data);
			addDCSValue(
				dcs, lot, datas);
		}
		catch (Exception e)
		{
			throw new MESException(e, MODULE_QM, "数据采集");
		}
	}
	
	/**
	 * 添加多条采集数据
	 * @param dcs		工艺参数集
	 * @param Lot		物料/批次
	 * @param key		采集项
	 * @param value		采集值
	 */
	private void addDCSValue(DataCollectionSet dcs,Lot lot,ArrayList<HashMap<String,Object>> datas) throws Exception
	{
		try
		{
			if (lot == null)
			{
				throwException("ERROR_67");
			}

			if (dcs == null)
			{
				throwException("ERROR_68");
			}

			RuntimeDCS runtimeDCS = lot.getDCS(dcs.getName());

			for (int i = 0; i < datas.size(); i++)
			{
				DCInstance dcInstance = runtimeDCS.createDCInstance();

				HashMap<String, Object> data = datas.get(i);
				Set<String> keySet = data.keySet();
				for (Iterator<String> iterator = keySet.iterator(); iterator.hasNext();)
				{
					String key = iterator.next();
					Object value = data.get(key);

					if(value == null)
					{
						continue;
					}
					
					DataCollectionItem dcsItem = dcs.getDataCollectionItem(key);
					if (dcsItem == null)
					{
						throw new Exception(getMessage("ERROR_69") + key);
					}

					String valueType = dcsItem.getType();
					if ("INTEGER".equals(valueType))
					{
						value = Integer.parseInt(value.toString());
					}
					else if ("FLOAT".equals(valueType))
					{
						value = Float.valueOf(value.toString());
					}
					else if ("STRING".equals(valueType))
					{
						value = value.toString();
					}
					else if ("BOOLEAN".equals(valueType))
					{
						value = (Integer.parseInt(value.toString()) == 1);
					}
					else if("DATETIME".equals(valueType))
					{
						value = (Time)value;
					}
					else
					{
						throw new Exception(getMessage("ERROR_70") + value.getClass());
					}

					dcInstance.setValue(
						key, value);
				}
			}

			Response response = runtimeDCS.save();
			if (response.isError())
			{
				throw new Exception(getMessage("ERROR_71") + response.getFirstErrorMessage());
			}
		}
		catch (Exception e)
		{
			throw new MESException(e, MODULE_QM, "数据采集");
		}
	}
	
	public Vector<HashMap<String, Object>> getAllDCSValue(Lot lot, String dcsName) throws MESException
	{
		try
		{
			Vector<HashMap<String, Object>> datas = new Vector<HashMap<String, Object>>();
			DataCollectionSet dcs = getFunctions().getDataCollectionSet(
				dcsName);
			if (dcs == null)
			{
				throw new Exception(getMessage("ERROR_72") + dcsName + getMessage("ERROR_73"));
			}
			Vector dcsItems = dcs.getDataCollectionItems();
			DCInstanceFilter dcInstanceFilter = getFunctions().createDCInstanceFilter(
				dcsName, lot);
//			dcInstanceFilter.setMaxRows(1);
			dcInstanceFilter.orderByLastSaveTime(false);
			Vector dcInstances = getFunctions().getFilteredDCInstances(
				dcInstanceFilter);
			if (dcInstances != null && dcInstances.size() > 0)
			{
				for (int i = 0; i < dcInstances.size(); i++)
				{
					HashMap<String, Object> data = new HashMap<String, Object>();
					DCInstance dcInstance = (DCInstance) dcInstances.get(i);
					for (int j = 0; j < dcsItems.size(); j++)
					{
						DataCollectionItem dcsItem = (DataCollectionItem) dcsItems.get(j);
						String itemName = dcsItem.getName();
						data.put(itemName, dcInstance.getValue(itemName));
					}
					datas.add(data);
				}
			}
			return datas;
		}
		catch (Exception e)
		{
			throw new MESException(e, MODULE_PM, "工艺参数采集");
		}
	}
	/**
	 * 获得最后一次某字段值
	 * @param lot		批次
	 * @param dcsName	工艺参数
	 * @param columnName字段
	 */
	public Object getLastestDCSItemValue(Lot lot,String dcsName, String columnName) throws MESException
	{
		try
		{
			DataCollectionSet dcs = getFunctions().getDataCollectionSet(dcsName);
			if(dcs == null)
			{
				throw new Exception(getMessage("ERROR_72") + dcsName + getMessage("ERROR_73"));
			}
			Vector dcsItems = dcs.getDataCollectionItems();
			DCInstanceFilter dcInstanceFilter = getFunctions().createDCInstanceFilter(
				dcsName, lot);
			dcInstanceFilter.setMaxRows(1);
			dcInstanceFilter.forParmNotEqualTo(columnName, null);
			dcInstanceFilter.orderByLastSaveTime(false);
			Vector dcInstances = getFunctions().getFilteredDCInstances(
				dcInstanceFilter);
			if (dcInstances != null && dcInstances.size() == 1)
			{
				DCInstance dcInstance = (DCInstance) dcInstances.firstElement();
				return dcInstance.getValue(columnName);
			}
			return null;
		}
		catch (Exception e)
		{
			throw new MESException(e, MODULE_PM, "工艺参数采集");
		}
	}
	
	/**
	 * 获得某批次的最后一次工艺参数
	 * @param lot		批次
	 * @param dcsName	工艺参数
	 */
	public HashMap<String, Object> getLastestDCSValue(Lot lot,String dcsName) throws MESException
	{
		try
		{
			HashMap<String, Object> data = new HashMap<String, Object>();
			DataCollectionSet dcs = getFunctions().getDataCollectionSet(dcsName);
			if(dcs == null)
			{
				throw new Exception(getMessage("ERROR_72") + dcsName + getMessage("ERROR_73"));
			}
			Vector dcsItems = dcs.getDataCollectionItems();
			DCInstanceFilter dcInstanceFilter = getFunctions().createDCInstanceFilter(
				dcsName, lot);
			dcInstanceFilter.setMaxRows(1);
			dcInstanceFilter.orderByLastSaveTime(false);
			Vector dcInstances = getFunctions().getFilteredDCInstances(
				dcInstanceFilter);
			if (dcInstances != null && dcInstances.size() == 1)
			{
				DCInstance dcInstance = (DCInstance) dcInstances.firstElement();
				for (int i = 0; i < dcsItems.size(); i++)
				{
					DataCollectionItem dcsItem = (DataCollectionItem) dcsItems.get(i);
					String itemName = dcsItem.getName();
					data.put(itemName, dcInstance.getValue(itemName));
				}
			}
			return data;
		}
		catch (Exception e)
		{
			throw new MESException(e, MODULE_PM, "工艺参数采集");
		}
	}
	
	
	
	/**
	 * 获得当前工位
	 */
	private WorkCenter getCurrentWorkCenter()
	{
		UIOrder uiOrder = getCurrentUIOrder();
		Lot lot = uiOrder.getLot();
		return getCurrentWorkCenter(lot);
	}
	
	/**
	 * 获得当前工位
	 */
	private WorkCenter getCurrentWorkCenter(Lot lot)
	{
		Step step = lot.getPresentRouteStep();
		String productionLineName = lot.getProductionLineName();
		ProductionLine productionLine = getFunctions().getProductionLineByName(productionLineName);
		Vector workCenters = productionLine.getWorkCenters();
		Vector stepWorkCenters = step.getWorkCenters();
		for (int j = 0; j < stepWorkCenters.size(); j++)
		{
			WorkCenter stepWorkCenter = (WorkCenter) stepWorkCenters.get(j);
			if (workCenters.contains(stepWorkCenter))
			{
				return stepWorkCenter;
			}
		}
		return null;
	}
	
	private WorkCenter getCurrentWorkCenter(Step step)
	{
		UIOrder uiOrder = getCurrentUIOrder();
		Lot lot = uiOrder.getLot();
		String productionLineName = lot.getProductionLineName();
		ProductionLine productionLine = getFunctions().getProductionLineByName(productionLineName);
		Vector workCenters = productionLine.getWorkCenters();
		Vector stepWorkCenters = step.getWorkCenters();
		for (int j = 0; j < stepWorkCenters.size(); j++)
		{
			WorkCenter stepWorkCenter = (WorkCenter) stepWorkCenters.get(j);
			if (workCenters.contains(stepWorkCenter))
			{
				return stepWorkCenter;
			}
		}
		return null;
	}
	
	/**
	 * 保存批次
	 * @param lotInfos	批次信息
	 * @param uiOrder	工单
	 */
	public void saveBatch(Vector<LotInfo> lotInfos,UIOrder uiOrder) throws Exception
	{
		Response response = getFunctions().getUserTransaction();
		if (response.isError())
		{
			throw new MESException(getMessage("ERROR_29"), MODULE_PM, "保存批次");
		}
		UserTransaction userTransaction = (UserTransaction) response.getResult();
		response = userTransaction.begin();
		if (response.isError())
		{
			throw new MESException(getMessage("ERROR_29"), MODULE_PM, "保存批次");
		}
		try
		{
			Lot originalLot = uiOrder.getLot();
			for (int i = 0; i < lotInfos.size(); i++)
			{
				LotInfo lotInfo = lotInfos.get(i);
				BigDecimal quantity = lotInfo.getQuantityValue();
				Lot lot = lotInfo.getLot();
				BillOfMaterials billOfMaterials = lotInfo.getBom();
				//新增的批次
				if(lot == null)
				{
					String lotName = lotInfo.getLotName();
//					if(!originalLot.getCurrentStatus().equals(ITrackedObjectConstants.STATUS_CLOSED))
//					{
//						response = originalLot.splitLot(lotName, quantity);
//						if(response.isError())
//						{
//							throw new Exception(getMessage("ERROR_74")+response.getFirstErrorMessage());
//						}
//						else
//						{
//							lot = (Lot) response.getResult();
//						}
//					}
//					else
//					{
						lot = getFunctions().createLot(lotName, uiOrder.getObject());
						lot.setOrderItem(uiOrder.getOrderName());
						lot.setQuantity(quantity);
						lot.setBulk();
						lot.setRouteName(originalLot.getRouteName());
						lot.setPartNumber(originalLot.getPartNumber());
						response = lot.save();
						if(response.isError())
						{
							throw new Exception(getMessage("ERROR_75")+response.getFirstErrorMessage());
						}
						else
						{
							Queue originalQueue = originalLot.getQueue();
							if(originalQueue != null)
							{
								response = lot.addToQueue(originalQueue);
								if(response.isError())
								{
									throw new Exception(getMessage("ERROR_76")+response.getFirstErrorMessage());
								}
							}
							else
							{
								throwException("ERROR_77");
							}
						}
//					}
				}
				//已经生成的批次
				else
				{
					if(!lot.getCurrentStatus().equals(ITrackedObjectConstants.STATUS_STR_CREATED))
					{
						continue;
					}
					
					BigDecimal originalQty = lot.getPreciseQuantity();
					if(originalQty.compareTo(quantity) != 0)
					{
						response = lot.changeBulkLotQuantity(getTrxTime(), quantity, null, null);
						if(response.isError())
						{
							throw new Exception(getMessage("ERROR_78")+response.getFirstErrorMessage());
						}
					}
				}
				
				if(lot == null)
				{
					throwException("ERROR_79");
				}
				
				if(billOfMaterials.isChanged())
				{
					BillOfMaterials buildtimeBom = getFunctions().createBOM();
					buildtimeBom.setBomName(billOfMaterials.getBomName());
					buildtimeBom.setBomRevision(billOfMaterials.getBomRevision());
					
					BigDecimal preQuantity = lot.getPreciseQuantity();
					
					Vector bomItems = billOfMaterials.getBomItems();
					for (int j = 0; j < bomItems.size(); j++)
					{
						BomItem bomItem = (BomItem) bomItems.get(j);
						BomItem newBomItem = getFunctions().createBomItem();
						newBomItem.setPartNumber(bomItem.getPartNumber());
						newBomItem.setPartRevision(bomItem.getPartRevision());
						newBomItem.setDescription(bomItem.getDescription());
						newBomItem.setBomItemName(bomItem.getBomItemName());
						newBomItem.setQuantity(bomItem.getPreciseQuantity().divide(preQuantity,3));
						newBomItem.setDecimalScale(bomItem.getDecimalScale());
						newBomItem.setUDA(
							bomItem.getUDA(0), 0);
						newBomItem.setUDA(
							bomItem.getUDA(1), 1);
						buildtimeBom.addBomItem(newBomItem);
					}
					
					response = lot.applyRuntimeBom(buildtimeBom);
					if(response.isError())
					{
						throwException("ERROR_80");
					}
				}
			}
			
			//匹配物料
			//获得所有的物料架并按物料号分类
			HashMap<String, Vector<Carrier>> carriersMap = new HashMap<String, Vector<Carrier>>();
			
			CarrierFilter carrierFilter = getFunctions().createCarrierFilter();
			carrierFilter.forUda2EqualTo(uiOrder.getOrderName());
			Vector<Carrier> carriers = getFunctions().getFilteredCarriers(
				carrierFilter);
			for (int i = 0; i < carriers.size(); i++)
			{
				Carrier carrier = carriers.get(i);
				Vector<Lot> materials = carrier.getAllLots();
				if(materials != null && materials.size()>0)
				{
					String partNumber = materials.firstElement().getPartNumber();
					Vector<Carrier> carrierMaterials = carriersMap.get(partNumber);
					if(carrierMaterials == null)
					{
						carrierMaterials = new Vector<Carrier>();
					}
					carrierMaterials.add(carrier);
					carriersMap.put(partNumber, carrierMaterials);
				}
			}
			
			//遍历所有批次并按物料架分配物料
			uiOrder.refresh();
			Vector<Lot> lots = uiOrder.getLots();
			for (int i = 0; i < lots.size(); i++)
			{
				Lot lot = lots.get(i);
				BillOfMaterials billOfMaterials = lot.getBillOfMaterials();
				Vector bomItems = billOfMaterials.getBomItems();
				for (int j = 0; j < bomItems.size(); j++)
				{
					BomItem bomItem = (BomItem) bomItems.get(j);
					String partNumber = bomItem.getPartNumber();
					BigDecimal materialQty = bomItem.getPreciseQuantity();
					carriers = carriersMap.get(partNumber);
					if(carriers == null)
					{
						continue;
					}
					Vector<Carrier> toRemovedCarriers = new Vector<Carrier>();
					//分配物料
					for (int k = 0; k < carriers.size(); k++)
					{
						Carrier carrier = carriers.get(k);
						//分配给该批次
						carrier.setUDA(lot.getName(), UDA_CARRIER_LOT);
						response = carrier.save();
						if(response.isError())
						{
							throw new Exception(getMessage("ERROR_81")+response.getFirstErrorMessage());
						}
						
						toRemovedCarriers.add(carrier);
						
						//计算物料总量
						Vector<Lot> materials = carrier.getAllLots();
						BigDecimal carrierQty = BigDecimal.ZERO;
						for (int l = 0; l < materials.size(); l++)
						{
							Lot material = materials.get(l);
							carrierQty = carrierQty.add(material.getPreciseQuantity());
						}
						
						//扣减需求量
						materialQty = materialQty.subtract(carrierQty);
						
						//若需求量已经分配完，则跳出进入下个物料
						if(materialQty.compareTo(BigDecimal.ZERO) < 1)
						{
							break;
						}
					}
					
					//删除已经分配的物料
					for (int k = 0; k < toRemovedCarriers.size(); k++)
					{
						carriers.remove(toRemovedCarriers.get(k));
					}
				}
			}
			
			response = userTransaction.commit();
			if (response.isError())
			{
				throwException("ERROR_29");
			}
		}
		catch (Exception e)
		{
			e.printStackTrace();
			userTransaction.rollback();
			throw new MESException(e, MODULE_PM, "保存批次");
		}
	}
	
	/**
	 * 拆肉
	 * @param lot		批次
	 * @param carrier	桶
	 */
	public void splitMaterials(Lot lot, Carrier carrier) throws MESException
	{
		Response response = getFunctions().getUserTransaction();
		if (response.isError())
		{
			throw new MESException(getMessage("ERROR_29"), MODULE_PM, "拆肉");
		}
		UserTransaction userTransaction = (UserTransaction) response.getResult();
		response = userTransaction.begin();
		if (response.isError())
		{
			throw new MESException(getMessage("ERROR_29"), MODULE_PM, "拆肉");
		}
		try
		{
			String orderName = lot.getOrderNumber();
			ATRowFilter atRowFilter = getFunctions().createATRowFilter(
				AT_TABLE_PM_MATERIAL_SPLIT);
			atRowFilter.forColumnNameEqualTo(
				AT_COLUMN_PM_MATERIAL_SPLIT_ORDER_NUMBER, orderName);
			atRowFilter.forColumnNameEqualTo(
				AT_COLUMN_PM_MATERIAL_SPLIT_CONSUMED, false);
			atRowFilter.addOrderATColumnBy(
				AT_COLUMN_PM_MATERIAL_SPLIT_SCAN_TIME, IFilterSortOrders.ASCENDING);
			Vector<ATRow> atRows = getFunctions().getFilteredATRows(
				atRowFilter, false);

			// 剩余装载量
			BigDecimal capacity = new BigDecimal(carrier.getCapacity());
			String lastMaterialName = null;
			String partNumber = null;
			BigDecimal lastQty = null;
			
			for (int i = 0; i < atRows.size(); i++)
			{
				ATRow atRowMaterial = atRows.get(i);
				atRowMaterial.refresh();
				BigDecimal qty = (BigDecimal) atRowMaterial
					.getValue(AT_COLUMN_PM_MATERIAL_SPLIT_QUANTITY);
				lastQty = qty;
				// 若剩余装载量小于原料量
				if (capacity.compareTo(qty) < 0)
				{
					break;
				}
				else
				{
					lastMaterialName = (String) atRowMaterial
						.getValue(AT_COLUMN_PM_MATERIAL_SPLIT_LOT_NAME);
					Lot lotMaterial = getFunctions().getLotByName(
						lastMaterialName);

					String materialPartNumber = lotMaterial.getPartNumber();
					if (partNumber == null)
					{
						partNumber = materialPartNumber;
					}
					else
					{
						// 若放的不是同一种物料
						if (!partNumber.equals(materialPartNumber))
						{
							break;
						}
					}

					// 将解冻架坐标去除
					String containerName = lotMaterial.getContainerName();
					if (StringUtils.isNotNull(containerName))
					{
						atRowFilter = getFunctions().createATRowFilter(
							"PMLocation");
						atRowFilter.forColumnNameEqualTo(
							"carrier_name", containerName);
						Vector containerAtRows = getFunctions().getFilteredATRows(
							atRowFilter, false);
						if (containerAtRows != null && containerAtRows.size() > 0)
						{
							ATRow atRow = (ATRow) containerAtRows.firstElement();
							atRow.delete(
								null, null, null);
						}
					}

					// 判断物料是否被拆分过
					if (lotMaterial.getLotType() == Lot.FLOW)
					{
						lotMaterial = getMaterialPartialLot(lotMaterial);
					}

					if (lotMaterial == null)
					{
						continue;
					}

					response = carrier.transferLotQuantity(
						getTrxTime(), lotMaterial, qty, null);
					if (response.isError())
					{
						throwException("ERROR_121");
					}
					else
					{
						atRowMaterial.setValue(
							AT_COLUMN_PM_MATERIAL_SPLIT_CONSUMED, true);
						response = atRowMaterial.save(
							null, null, null);
						if (response.isError())
						{
							throwException("ERROR_122");
						}
						else
						{
							capacity = capacity.subtract(qty);
						}
					}
				}
			}

			carrier.refresh();
			Vector allLots = carrier.getAllLots();
			if (allLots.size() == 0)
			{
				getFunctions().dialogError("当前拆肉批次数量为"+lastQty.setScale(2,3)+",桶重量为"+capacity+",\n无法将该批次放入桶中");
			}
			else
			{
				carrier.setUDA(
					lot.getName(), UDA_CARRIER_LOT); // 桶关联批次
				carrier.setUDA(
					String.valueOf(carrier.getCapacity() - capacity.intValue()),
					UDA_CARRIER_QUANTITY); // 修正值
				carrier.setUDA(
					orderName, UDA_CARRIER_ORDER_NUMBER); // 桶关联工单
				carrier.setUDA(
					lastMaterialName, UDA_CARRIER_LAST_MATERIAL); // 最后一个消耗的物料号
				response = carrier.save();
				if (response.isError())
				{
					throwException("ERROR_123");
				}
			}
			response = userTransaction.commit();
			if (response.isError())
			{
				throwException("ERROR_29");
			}

		}
		catch (Exception e)
		{
			e.printStackTrace();
			userTransaction.rollback();
			throw new MESException(e, MODULE_PM, "拆肉");
		}
	}
	
	/**
	 * 获得未装桶的物料
	 */
	private Lot getMaterialPartialLot(Lot lotMaterial)
	{
		long lotKey = lotMaterial.getKey();
		String sql = "select tobj_status_key from dbo.LOT_FLOW_TRACKING where lot_key = '"+lotKey+"' and lot_type = 5  and container_name is not null and container_name not like 'T%' and container_name like 'JDJ%'";
		Vector results = getFunctions().getArrayDataFromActive(sql);
		long tsKey = -1;
		if(results.size() > 0)
		{
			String partialLotKey = ((String[])results.firstElement())[0];
			tsKey = Long.parseLong(partialLotKey);
		}
		
		Vector<Lot> partialLots = lotMaterial.getPartialLots();
		for (int i = 0; i < partialLots.size(); i++)
		{
			Lot lot = partialLots.get(i);
			if (lot.getTObjStatusKey() == tsKey)
			{
				return lot;
			}
		}
		return null;
	}
	
	

	/**
	 * 消耗桶
	 * @param lot		批次
	 * @param carriers	桶
	 */
	public void consumeCarriers(Lot lot, Vector<Carrier> carriers) throws MESException
	{
		Response response = getFunctions().getUserTransaction();
		if (response.isError())
		{
			throw new MESException(getMessage("ERROR_29"), MODULE_PM, "绞肉");
		}
		UserTransaction userTransaction = (UserTransaction) response.getResult();
		response = userTransaction.begin();
		if (response.isError())
		{
			throw new MESException(getMessage("ERROR_29"), MODULE_PM, "绞肉");
		}
		try
		{
		    startLotInCurrentStep(lot);
		    
		    if(lot.getLotType() == Lot.FLOW)
		    {
		    	lot = getCurrentStepPartialLot(lot, getCurrentStep());
		    }
			
			ConsumptionSet consumptionSet = lot.createConsumptionSet();
			BillOfMaterials bom = lot.getBillOfMaterials();

			// 消耗桶
			for (int i = 0; i < carriers.size(); i++)
			{
				Carrier carrier = carriers.get(i);
				String qtyStr = carrier.getUDA(3);
				BigDecimal consumedQty = StringUtils.isNull(qtyStr)?new BigDecimal(carrier.getCapacity()):new BigDecimal(qtyStr);
				Vector<Lot> lotMaterials = carrier.getAllLots();
				// 消耗桶内物料
				for (int j = 0; j < lotMaterials.size(); j++)
				{
					Lot lotMaterial = lotMaterials.get(j);
					BigDecimal lotMaterialQty = lotMaterial.getPreciseQuantity();
					// 扣减完成
					if (consumedQty.equals(BigDecimal.ZERO))
					{
						break;
					}
					// 修正物料数量
					if (consumedQty.compareTo(lotMaterialQty) < 0)
					{
						response = lotMaterial.changeBulkLotQuantity(
							getTrxTime(), consumedQty, null, "修正值");
						if (response.isError())
						{
							throwException("ERROR_82");
						}
						else
						{
							lotMaterialQty = lotMaterial.getPreciseQuantity();
						}
					}
					// 扣减物料
					consumedQty = consumedQty.subtract(lotMaterialQty);

					String bomItemName = lotMaterial.getPartNumber();
					BomItem bomItem = bom.getBomItem(bomItemName);
					if (bomItem != null)
					{
						consumptionSet.addConsumedPart(
							bomItem, lotMaterial, lotMaterialQty);
					}
					else
					{
						throw new Exception(getMessage("ERROR_83") + bomItemName + getMessage("ERROR_84"));
					}
				}
			}

			// 保存消耗数据
			response = consumptionSet.save(
				getTrxTime(), false, false, false, "消耗桶", null);
			if (response.isOk())
			{
				// 解除桶和批次的绑定关系
				for (int i = 0; i < carriers.size(); i++)
				{
					Carrier carrier = carriers.get(i);
					carrier.setUDA(
						null, 1);
					carrier.setUDA(
						null, 2);
					carrier.setUDA(
						null, 3);
					response = carrier.save();
					if (response.isOk())
					{
						response = carrier.removeAll();
						if (response.isError())
						{
							throwException("ERROR_85");
						}
					}
					else
					{
						throwException("ERROR_86");
					}
				}
			}
			else
			{
				throw new Exception(getMessage("ERROR_87") + response.getFirstErrorMessage());
			}
			
			response = userTransaction.commit();
			if (response.isError())
			{
				throwException("ERROR_29");
			}
		}
		catch (Exception e)
		{
			e.printStackTrace();
			userTransaction.rollback();
			throw new MESException(e, MODULE_PM, "绞肉");
		}
	}
	
	/**
	 * 消耗桶内物料和添加剂
	 * @param lot				当前批次
	 * @param carrier			滚揉桶
	 * @param consumptionSet	添加剂消耗集合
	 */
	public void consumeCarrierAndAdditivePrescription(Lot lot,Carrier carrier,ConsumptionSet consumptionSet) throws Exception
	{
		Response response = getFunctions().getUserTransaction();
		if (response.isError())
		{
			throw new MESException(getMessage("ERROR_29"), MODULE_PM, "滚揉");
		}
		UserTransaction userTransaction = (UserTransaction) response.getResult();
		response = userTransaction.begin();
		if (response.isError())
		{
			throw new MESException(getMessage("ERROR_29"), MODULE_PM, "滚揉");
		}
		try
		{
			if(lot == null)
			{
				throwException("ERROR_88");
			}
			
			if(carrier == null)
			{
				throwException("ERROR_89");
			}
			
			if(consumptionSet == null)
			{
				throwException("ERROR_90");
			}
			

			BillOfMaterials bom = lot.getBillOfMaterials();
			BigDecimal consumedQty = new BigDecimal(carrier.getUDA(3));
			Vector<Lot> lotMaterials = carrier.getAllLots();
			// 消耗桶内物料
			for (int j = 0; j < lotMaterials.size(); j++)
			{
				Lot lotMaterial = lotMaterials.get(j);
				BigDecimal lotMaterialQty = lotMaterial.getPreciseQuantity();
				// 扣减完成
				if (consumedQty.equals(BigDecimal.ZERO))
				{
					break;
				}
				// 修正物料数量
				if (consumedQty.compareTo(lotMaterialQty) < 0)
				{
					response = lotMaterial.changeBulkLotQuantity(
						getTrxTime(), consumedQty, null, "修正值");
					if (response.isError())
					{
						throwException("ERROR_91");
					}
					else
					{
						lotMaterialQty = lotMaterial.getPreciseQuantity();
					}
				}
				// 扣减物料
				consumedQty = consumedQty.subtract(lotMaterialQty);

				String bomItemName = lotMaterial.getPartNumber();
				BomItem bomItem = bom.getBomItem(bomItemName);
				if (bomItem != null)
				{
					consumptionSet.addConsumedPart(
						bomItem, lotMaterial, lotMaterialQty);
				}
				else
				{
					throw new Exception(getMessage("ERROR_92") + bomItemName + getMessage("ERROR_93"));
				}
			}
		
			carrier.setUDA(
				null, 1);
			carrier.setUDA(
				null, 2);
			carrier.setUDA(
				null, 3);
			response = carrier.save();
			if (response.isOk())
			{
				response = carrier.removeAll();
				if (response.isError())
				{
					throwException("ERROR_94");
				}
			}
			else
			{
				throwException("ERROR_95");
			}
			
			// 保存消耗数据
			response = consumptionSet.save(getTrxTime(), false, false, false, "消耗桶", null);
			if(response.isError())
			{
				throw new Exception(getMessage("ERROR_96")+response.getFirstErrorMessage());
			}
			
			response = userTransaction.commit();
			if (response.isError())
			{
				throwException("ERROR_29");
			}
		}
		catch (Exception e)
		{
			userTransaction.rollback();
			throw new MESException(e, MODULE_PM, "滚揉");
		}
	}
	
	/**
	 * 将原料倒入桶
	 * @param lots				原料
	 * @param carrier			桶
	 */
	public void transferMaterialToCarrier(Carrier originalCarrier,Carrier carrier) throws Exception
	{
		Response response = getFunctions().getUserTransaction();
		if (response.isError())
		{
			throw new MESException(getMessage("ERROR_29"), MODULE_PM, "滚揉");
		}
		UserTransaction userTransaction = (UserTransaction) response.getResult();
		response = userTransaction.begin();
		if (response.isError())
		{
			throw new MESException(getMessage("ERROR_29"), MODULE_PM, "滚揉");
		}
		try
		{
			if(carrier == null)
			{
				throwException("ERROR_97");
			}
			
			if(originalCarrier == null)
			{
				throwException("ERROR_98");
			}
			
			Vector lots = originalCarrier.getAllLoadedLots();
			
			for (int i = 0; i < lots.size(); i++)
			{
				Lot lot = (Lot) lots.get(i);
				response = carrier.transferLot(lot);
				if(response.isError())
				{
					throw new Exception(getMessage("ERROR_99")+response.getFirstErrorMessage());
				}
			}
			
			//保存新桶数据
			carrier.setUDA(
				originalCarrier.getUDA(UDA_CARRIER_LOT), UDA_CARRIER_LOT);
			carrier.setUDA(
				originalCarrier.getUDA(UDA_CARRIER_ORDER_NUMBER), UDA_CARRIER_ORDER_NUMBER);
			carrier.setUDA(
				originalCarrier.getUDA(UDA_CARRIER_QUANTITY), UDA_CARRIER_QUANTITY);
			response = originalCarrier.save();
			if(response.isError())
			{
				throwException("ERROR_100");
			}
			
			//接触桶的绑定关系
			originalCarrier.setUDA(
				null, 1);
			originalCarrier.setUDA(
				null, 2);
			originalCarrier.setUDA(
				null, 3);
			response = originalCarrier.save();
			if (response.isOk())
			{
				response = originalCarrier.removeAll();
				if (response.isError())
				{
					throwException("ERROR_101");
				}
			}
			else
			{
				throwException("ERROR_102");
			}
			
			response = userTransaction.commit();
			if (response.isError())
			{
				throwException("ERROR_29");
			}
		}
		catch (Exception e)
		{
			userTransaction.rollback();
			throw new MESException(e, MODULE_PM, "滚揉");
		}
	}
	
	/**
	 * 消耗物料 不保存
	 * @param lot				批次
	 * @param material			物料
	 * @param consumptionSet	消耗集合
	 * @param qty				数量
	 */
	public ConsumptionSet consumeLot(Lot lot,Lot material,ConsumptionSet consumptionSet,BigDecimal qty) throws Exception
	{
		try
		{
			if(lot == null)
			{
				throwException("ERROR_103");
			}
			
			if(material == null)
			{
				throwException("ERROR_104");
			}
			
			if(consumptionSet == null)
			{
				throwException("ERROR_105");
			}
			
			BillOfMaterials billOfMaterials = lot.getBillOfMaterials();
			String materialPartNumber = material.getPartNumber();
			BomItem bomItem = billOfMaterials.getBomItem(materialPartNumber);
			if(bomItem == null)
			{
				throw new Exception(getMessage("ERROR_106")+materialPartNumber+getMessage("ERROR_107"));
			}
			
			consumptionSet.addConsumedPart(bomItem, material, qty==null?material.getPreciseQuantity():qty);
			return consumptionSet;
		}
		catch (Exception e)
		{
			throw new MESException(e, MODULE_PM, "消耗物料");
		}
	}
	
	/**
	 * 打印托盘条码
	 * @param lot			批次
	 * @param qty			托盘箱数
	 */
	public Box printBoxBarcode(Lot lot,Integer qty) throws Exception
	{
		Response response = getFunctions().getUserTransaction();
		if (response.isError())
		{
			throw new MESException(getMessage("ERROR_29"), MODULE_PM, "不可食量");
		}
		UserTransaction userTransaction = (UserTransaction) response.getResult();
		response = userTransaction.begin();
		if (response.isError())
		{
			throw new MESException(getMessage("ERROR_29"), MODULE_PM, "不可食量");
		}
		try
		{
			if(lot == null)
			{
				throwException("ERROR_103");
			}
			
			String lotName = lot.getName();
			String orderNumber = lot.getOrderNumber();
			
			String supplier = lot.getUDA(UDA_LOT_SUPPLIER);
			String supplierLotNo = lot.getUDA(UDA_LOT_SUPPLIER_LOTNO);
			
			//获得条码
			PrintComponent printComponent = new PrintComponent(getFunctions());
			
			Time time = getTrxTime();
			int hour = time.getHour();
			String sequence = lotName.substring(lotName.length()-2, lotName.length());
			String productionLineName = lot.getProductionLineName();
			String printLot = sequence+"-"+productionLineName+"-"+hour+",";
			
			String barcode = printComponent.getBarcodeFromWMS(lot.getPart(), supplier, supplierLotNo, orderNumber, productionLineName, printLot, qty.toString(),2);
			
			Box box = getFunctions().createBox(barcode);
			box.setUDA(qty.toString(),UDA_BOX_QUANTITY);
			box.setUDA(lotName, UDA_BOX_LOT_NAME);
			box.setUDA(orderNumber, UDA_BOX_ORDER_NUMBER);
			box.setUDT(time, UDT_BOX_CREATION_TIME);
			response = box.save();
			if(response.isError())
			{
				throwException("ERROR_108");
			}
			
			barcode = generateBoxBarcode(barcode,box,lot,printLot);
			printComponent.printBarCode(barcode, IPrintConstants.BARCODE_TYPE_LOT);
			PrintComponent.logPrintRecord(getFunctions(), barcode,IPrintConstants.BARCODE_TYPE_LOT,orderNumber,productionLineName,lot.getPart().getDescription());
			
			response = userTransaction.commit();
			if (response.isError())
			{
				throwException("ERROR_29");
			}
			return box;
		}
		catch (Exception e)
		{
			e.printStackTrace();
			userTransaction.rollback();
			throw new MESException(e, MODULE_PM, "不可食量");
		}
	}
	
	/**
	 * 验证投料是否合法
	 * @param lot			批次
	 * @param lotMaterial	物料
	 * @param qty			数量
	 */
	public void validateMaterialValid(Lot lot,Lot lotMaterial,BigDecimal qty) throws Exception
	{
		
		try{
			if(lot == null)
			{
				throw new Exception("批次不允许为空");
			}
			
			if(lotMaterial == null)
			{
				throw new Exception("物料不允许为空");
			}
			
			if(qty == null)
			{
				qty = lotMaterial.getPreciseQuantity();
			}
			
			String materialPartNumber = lotMaterial.getPartNumber();
			BillOfMaterials runtimeBom = lot.getBillOfMaterials();
			BomItem bomItem = runtimeBom.getBomItem(materialPartNumber);
			if(bomItem == null)
			{
				throw new Exception("不允许消耗该物料");
			}
			
			BigDecimal maxQty = bomItem.getPreciseQuantity();
			//如果物料是添加剂，则还需要加上偏差值
			Part materialPart = lotMaterial.getPart();
			if("503".equals(materialPart.getUDA(UDA_PART_CLASS2)))
			{
				//获得最高偏差值
				maxQty = new BigDecimal(lotMaterial.getUDA(UDA_LOT_IS_SCANNED));
			}
			
			
			BigDecimal consumedQty = bomItem.getPreciseQuantityConsumed();
			BigDecimal remainQty = maxQty.subtract(consumedQty);
			
			if(remainQty.compareTo(qty) < 0)
			{
				throw new Exception("物料消耗不允许超过标准值");
			}
		}catch (Exception e) {
			throw new MESException(e, MODULE_PM, "物料验证");
		}
		
	}
	
	/**
	 * 生成成品条码
	 * @param barcode	成品流水号
	 * @param box		托盘
	 * @param lot		批次
	 */
	private String generateBoxBarcode(String barcode, Box box, Lot lot,String printLot)
	{
		Time time = box.getUDT(UDT_BOX_CREATION_TIME);
		String userName = getFunctions().getCurrentUser().getName();
		Part part = lot.getPart();
		String partName = part.getDescription();
		String timeStr = DateTimeUtils.formatDate(time, "yyyy-MM-dd");
		barcode = barcode+","+partName+","+timeStr+","+userName+","+printLot;
		return barcode;
	}

	/**
	 * 打印添加剂条码
	 * @param mainMaterialNumber 	大包装袋条码
	 * @param weightStr			  	称量重量
	 * @param uiOrder			  	称量的工单
	 * @param additivePrescription	添加剂配方
	 * @param lotQuantity			批次重量
	 * @param isStandard			是否为标准批
	 */
	public Lot printAdditiveBarcode(String mainMaterialNumber,String weightStr,UIOrder uiOrder,AdditivePrescription additivePrescription,String lotQuantity,boolean isStandard) throws Exception
	{
		Response response = getFunctions().getUserTransaction();
		if (response.isError())
		{
			throw new MESException(getMessage("ERROR_29"), MODULE_PM, "添加剂条码");
		}
		UserTransaction userTransaction = (UserTransaction) response.getResult();
		response = userTransaction.begin();
		if (response.isError())
		{
			throw new MESException(getMessage("ERROR_29"), MODULE_PM, "添加剂条码");
		}
		try
		{
			
			//计算理论重量
			BigDecimal range = new BigDecimal(additivePrescription.getErrorRange());				//偏差值
			BigDecimal itemQty = new BigDecimal(additivePrescription.getItemQty());					//添加剂重量
			BigDecimal standardQty = new BigDecimal(additivePrescription.getStandardWeight());		//标准原料重量
			BigDecimal orderQuantity = BigDecimal.ZERO;												//批次重量
			if(isStandard)
			{
				orderQuantity = standardQty;
			}
			else
			{
				orderQuantity = new BigDecimal(lotQuantity);
			}
			
			BigDecimal calcQty = itemQty.divide(standardQty,3).multiply(orderQuantity); 				//理论重量
			BigDecimal weight = new BigDecimal(weightStr);											//实际重量
			
			//计算是否超出偏差值
			BigDecimal rangeLower = (itemQty.multiply(orderQuantity).divide(standardQty.add(range),3)).setScale(2,3);	//下限
			BigDecimal rangeUpper = (itemQty.multiply(orderQuantity).divide(standardQty.subtract(range),3)).setScale(2,3);			//上限
			
			if(weight.compareTo(rangeLower) < 0 || weight.compareTo(rangeUpper) > 0)
			{
				int result = getFunctions().dialogYesNo("确认", "本次称重不符合上下限标准，是否继续打印？");
				if(result == 7)
				{
					response = userTransaction.commit();
					return null;
				}
			}
			
			Lot mainLot = getFunctions().getLotByName(mainMaterialNumber);		
			BigDecimal currentQty = mainLot.getPreciseQuantity();									//大包剩余重量
			//若大包剩余重量小于实际重量
			if(currentQty.compareTo(weight) < 0)
			{
				response = mainLot.changeBulkLotQuantity(getTrxTime(), weight, null, null);
				if(response.isError())
				{
					throw new Exception(getMessage("ERROR_111")+response.getFirstErrorMessage());
				}
			}
			
			//获得条码
			PrintComponent printComponent = new PrintComponent(getFunctions());
			
			String barcode = printComponent.generateTestBarcode("ADD");
			if(StringUtils.isNull(barcode))
			{
				throwException("ERROR_110");
			}
			
			response = mainLot.splitLot(barcode, weight);
			if(response.isError())
			{
				throw new Exception(getMessage("ERROR_112")+response.getFirstErrorMessage());
			}
			Lot lot = (Lot) response.getResult();
			
			lot.setUDA(uiOrder.getOrderName(),UDA_LOT_ORDER_NUMBER);
			lot.setUDA(calcQty.toString(), 4);
			lot.setUDA(isStandard?1:0, UDA_LOT_IS_STANDARD);
			lot.setUDA(orderQuantity.setScale(2, 3).floatValue(), UDA_LOT_STANDARD_WEIGHT);
			lot.setUDA(rangeUpper.setScale(4,3).toString(), UDA_LOT_IS_SCANNED);
			
			response = lot.save();
			if(response.isError())
			{
				throw new Exception(getMessage("ERROR_113")+response.getFirstErrorMessage());
			}
			
			barcode = generateMaterialBarcode(barcode, lot);
			printComponent.printBarCode(barcode, IPrintConstants.BARCODE_TYPE_MATERIAL);
			PrintComponent.logPrintRecord(getFunctions(), barcode,IPrintConstants.BARCODE_TYPE_MATERIAL,uiOrder.getOrderName(),uiOrder.getProductionLineValue(),lot.getDescription());
			
			response = userTransaction.commit();
			if (response.isError())
			{
				throwException("ERROR_29");
			}
			return lot;
		}
		catch (Exception e)
		{
			e.printStackTrace();
			userTransaction.rollback();
			throw new MESException(e, MODULE_PM, "添加剂条码");
		}
	}
	
	/**
	 * 获得异物登记 记录
	 * @param lotName		批次号
	 * @param orderName		工单号
	 * @param stepName		工序名称
	 * @param time			时间
	 */
	public Vector<ForeignMatter> getAbnormalRecords(String lotName,String orderName,String stepName,Time time) throws MESException
	{
		try
		{
			ATRowFilter atRowFilter = getFunctions().createATRowFilter(
				IATConstants.AT_TABLE_QM_FOREIGN_MATTER);
			if (StringUtils.isNotNull(lotName))
			{
				atRowFilter.forColumnNameEqualTo(
					IATConstants.AT_COLUMN_QM_FOREIGN_MATTER_PROD_BATCH, lotName);
			}
			if(StringUtils.isNotNull(orderName))
			{
				atRowFilter.forColumnNameEqualTo(IATConstants.AT_COLUMN_QM_FOREIGN_MATTER_ORDER_NUMBER, orderName);
			}
//					UIOrder uiOrder = getUIOrder(orderName);
//					Route route = uiOrder.getRouteValue();
//					Vector steps = route.getSteps();
//					for (int i = 0; i < steps.size(); i++)
//					{
//						Step step = (Step) steps.get(i);
//						String operationName = step.getOperationName();
//						if(stepName.equals(operationName))
//						{
//							atRowFilter.forColumnNameEqualTo(IATConstants.AT_COLUMN_QM_FOREIGN_MATTER_ROUTE_STEP_NAME, step.getName());
//						}
//					}
//				}
			
			
			if(StringUtils.isNotNull(stepName))
			{
				atRowFilter.forColumnNameEqualTo(IATConstants.AT_COLUMN_QM_FOREIGN_MATTER_ROUTE_STEP_NAME, stepName);
			}
			if(time != null)
			{
				atRowFilter.forColumnNameGreaterThanOrEqualTo(IATConstants.AT_COLUMN_QM_FOREIGN_MATTER_REC_TIME, getDayStart(time));
				atRowFilter.forColumnNameLessThanOrEqualTo(IATConstants.AT_COLUMN_QM_FOREIGN_MATTER_REC_TIME, getDayEnd(time));
			}
			Vector atRows = getFunctions().getFilteredATRows(atRowFilter, false);
			Vector<ForeignMatter> foreignMatters = new Vector<ForeignMatter>();
			for (int i = 0; i < atRows.size(); i++)
			{
				foreignMatters.add(new ForeignMatter((ATRow) atRows.get(i)));
			}
			return foreignMatters;
		}
		catch (Exception e)
		{
			throw new MESException(e, MODULE_PM, "异物登记");
		}
	}
	
	/**
	 * 查询物料
	 * @param materialType	物料类型
	 */
	public Vector<Lot> getMaterials(int materialType,String orderName)
	{
		LotFilter lotFilter = getFunctions().createLotFilter();
		lotFilter.forStatusNotEqualTo(ITrackedObjectConstants.STATUS_STR_CLOSED);
		if(StringUtils.isNotNull(orderName))
		{
			lotFilter.forUda3EqualTo(orderName);
		}
		
		if(materialType == IMaterialType.STACKING)
		{
			PartFilter partFilter = getFunctions().createPartFilter();
			partFilter.forUdaEqualTo(UDA_PART_CLASS2, "602");
			lotFilter.addSearchBy(ILotFilterAttributes.PART_NUMBER, IFilterComparisonOperators.IN, IPartFilterAttributes.NUMBER, partFilter);
		}
		else if(materialType == IMaterialType.PACKING)
		{
			PartFilter partFilter = getFunctions().createPartFilter();
			partFilter.forUdaEqualTo(UDA_PART_CLASS2, "601");
			lotFilter.addSearchBy(ILotFilterAttributes.PART_NUMBER, IFilterComparisonOperators.IN, IPartFilterAttributes.NUMBER, partFilter);
		}
		else if(materialType == IMaterialType.ADDITIVE_PRESCRIPTION)
		{
			PartFilter partFilter = getFunctions().createPartFilter();
			partFilter.forUdaEqualTo(UDA_PART_CLASS2, "503");
			lotFilter.addSearchBy(ILotFilterAttributes.PART_NUMBER, IFilterComparisonOperators.IN, IPartFilterAttributes.NUMBER, partFilter);
			lotFilter.forLotNameStartingWith("ADD");
		}
		
		return getFunctions().getFilteredLots(lotFilter);
	}
	
	/**
	 * 处理PLC数据事件(开始、结束信号)
	 * @param groupDataEvent	PLC dataChange事件
	 * @param esMessageGroup	发送消息组件
	 */
	public void handleStartOrStopSign(GroupDataEvent groupDataEvent,MessageGroupEventContainer messageGroup)
	{
		try
		{
			if (groupDataEvent == null || messageGroup == null)
			{
				throwException("the plc data or message component can not be null");
			}

			if (groupDataEvent.isGoodQuality())
			{
				LiveDataItem[] items = groupDataEvent.getItems();
				for (int i = 0; i < items.length; i++)
				{
					String plcPath = items[i].getName();
					String[] plcPaths = plcPath.split("\\.");
					if (plcPaths.length >= 5)
					{
						String productionLine = plcPaths[2];
						String workCenterName = plcPaths[3];

						// 获得当前工步上的批次
						Lot lot = getLot(
							productionLine, workCenterName);
						if (lot == null)
							continue;

						RuntimeDCS signDCS = lot.getDCS(IDCSConstants.DCS_TABLE_SIGN);

						String tagName = plcPaths[3]; // TAG名称
						ItemData itemData = groupDataEvent.getData(items[i]);
						Integer value = Integer.parseInt(itemData.getValue().toString()); // 信号值

						Integer signValue = null;

						String msgId = null; // 消息名称

						if (value.equals(IOPCConstants.SIGN_TRUE))
						{
							// 甜不辣启动信号
							if (tagName.equals(IOPCConstants.TAG_L2_TBL_SIGN_START)
								|| tagName.equals(IOPCConstants.TAG_L1_TBL_SIGN_START))
							{
								signValue = IOPCConstants.SIGN_TRUE;
							}
							// 甜不辣停止信号
							else if (tagName.equals(IOPCConstants.TAG_L2_TBL_SIGN_STOP)
								|| tagName.equals(IOPCConstants.TAG_L1_TBL_SIGN_STOP))
							{
								signValue = IOPCConstants.SIGN_FALSE;
								if (IOPCConstants.PL_L1.equals(productionLine))
								{
									msgId = IMessageSign.MSG_ID_TBL_L1;
								}
								else if (IOPCConstants.PL_L2.equals(productionLine))
								{
									msgId = IMessageSign.MSG_ID_TBL_L2;
								}
							}
							// 奶水打浆启动信号
							else if (tagName.equals(IOPCConstants.TAG_MILK_SIGN_START))
							{
								signValue = IOPCConstants.SIGN_TRUE;
							}
							// 奶水打浆停止信号
							else if (tagName.equals(IOPCConstants.TAG_MILK_SIGN_STOP))
							{
								signValue = IOPCConstants.SIGN_FALSE;
								msgId = IMessageSign.MSG_ID_MILK;
							}
							//成型机启动信号、滚揉开始信号、预冷机启动信号、搅拌机开始信号
							else if (tagName.equals(IOPCConstants.TAG_FORMING_START)
								|| tagName.equals(IOPCConstants.TAG_KNEAD_START)
								|| tagName.equals(IOPCConstants.TAG_PRE_COLD_START)
								|| tagName.equals(IOPCConstants.TAG_BLENDER_START))
							{
								signValue = IOPCConstants.SIGN_TRUE;
							}
							//成型机停止信号、滚揉结束信号、预冷机停止信号、搅拌机结束信号
							else if (tagName.equals(IOPCConstants.TAG_FORMING_STOP)
								|| tagName.equals(IOPCConstants.TAG_KNEAD_STOP)
								|| tagName.equals(IOPCConstants.TAG_PRE_COLD_STOP)
								|| tagName.equals(IOPCConstants.TAG_BLENDER_STOP))
							{
								signValue = IOPCConstants.SIGN_FALSE;
							}

							//若是裹浆粉工序，则需要发送给客户端
							if (workCenterName.equals(IOPCConstants.WC_DUST))
							{
								// 将信号发送至Client端
								if (StringUtils.isNotNull(msgId))
								{
									messageGroup.send(
										msgId, IMessageSign.MSG_BODY_END);
								}
							}
						}

						if (signValue != null)
						{
							DCInstance dcInstance = signDCS.createDCInstance();
							dcInstance.setValue(
								IDCSConstants.DCS_COLUMN_SIGN_SIGN_VALUE, signValue);
							dcInstance.setValue(
								IDCSConstants.DCS_COLUMN_SIGN_SIGN_TYPE, workCenterName);
							dcInstance.setValue(
								IDCSConstants.DCS_COLUMN_SIGN_PRODUCTION_LINE, productionLine);
						}

						if (signDCS.isChanged())
						{
							Response response = signDCS.save();
							if (response.isError())
							{
								throwException("保存信号失败，原因为" + response.getFirstErrorMessage());
							}
						}
					}
				}
			}
		}
		catch (Exception e)
		{
			System.err.println("设备PLC采集失败，原因为"+e.getLocalizedMessage());
		}
	}

	/**
	 * 根据WorkCenter名称获得当前批次
	 */
	private Lot getLot(String productionLine,String workCenterName)
	{
		LotFilter lotFilter = getFunctions().createLotFilter();
		lotFilter.forWorkCenterNameEqualTo(workCenterName);
		lotFilter.forProductionLineNameEqualTo(productionLine);
		lotFilter.forStatusEqualTo(ITrackedObjectConstants.STATUS_STR_STARTED);
		Vector lots = getFunctions().getFilteredLots(lotFilter);
		if(lots != null && lots.size() > 0)
		{
			return (Lot) lots.firstElement();
		}
		return null;
	}
	
	/**
	 * 请求采集数据
	 */
	public void notifyCollectionData(LiveDataEventContainer liveDataEventContainer)
	{
		LiveDataServer[] servers = liveDataEventContainer.getServers();
		for (int i = 0; i < servers.length; i++)
		{
			try{
				if(servers[i].getFTLDServer().isConnected())
				{
					LiveDataGroup group = servers[i].getGroup(IOPCConstants.GROUP_READ);
					if(group != null)
					{
						LiveDataItems allItemsToRead = group.getItems();
						group.asyncRead(allItemsToRead.getItems());
					}
				}
			}catch (Exception e) {
				System.err.println(e);
			}
		}
	}
	
	/**
	 * 采集数据
	 */
	public void collectionData(GroupDataEvent groupDataEvent)
	{
		try
		{
			LiveDataItem[] items = groupDataEvent.getItems();
			
			HashMap<String,Vector<String>> pl_wc_map = new HashMap<String, Vector<String>>();
			HashMap<String,Vector<LiveDataItem>> wc_ldItem_map = new HashMap<String, Vector<LiveDataItem>>();
			
			//将采集得到的数据按产线-工位-采集点归类
			for (int i = 0; i < items.length; i++)
			{
				String plcPath = items[i].getName();
				String[] plcPaths = plcPath.split("\\.");
				if(plcPaths.length >= 5)
				{
					String productionLine = plcPaths[2];
					String workCenterName = plcPaths[3];
					if(!pl_wc_map.containsKey(productionLine))
					{
						pl_wc_map.put(productionLine, new Vector<String>());
					}
					
					Vector<String> workCenters = pl_wc_map.get(productionLine);
					
					if(!wc_ldItem_map.containsKey(workCenterName))
					{
						wc_ldItem_map.put(workCenterName, new Vector<LiveDataItem>());
						workCenters.add(workCenterName);
					}
					
					Vector<LiveDataItem> liveDataItems = wc_ldItem_map.get(workCenterName);
					
					if(!liveDataItems.contains(items[i]))
					{
						liveDataItems.add(items[i]);
					}
				}
			}
			
			//保存数据
			Set<String> keySet = pl_wc_map.keySet();
			for (String productionLineName : keySet)
			{
				Vector<String> workCenters = pl_wc_map.get(productionLineName);
				for (int i = 0; i < workCenters.size(); i++)
				{
					String workCenterName = workCenters.get(i);
					
					Lot lot = getLot(productionLineName, workCenterName);
					if(lot != null)
					{
						String dcsName = getMachineDCS(lot);
						if (StringUtils.isNotNull(dcsName))
						{
							RuntimeDCS runtimeDCS = lot.getDCS(dcsName);
							DCInstance dcInstance = runtimeDCS.createDCInstance();
							Vector<LiveDataItem> liveDataItems = wc_ldItem_map.get(workCenterName);
							for (int j = 0; j < liveDataItems.size(); j++)
							{
								LiveDataItem liveDataItem = liveDataItems.get(i);
								String plcPath = liveDataItem.getName();
								String[] plcPaths = plcPath.split("\\.");
								if (plcPaths.length == 5)
								{
									String tagName = plcPaths[4]; //tag名称，同时也是DCS Column名称
									ItemData itemData = groupDataEvent.getData(items[i]);
									Object value = itemData.getValue(); //信号值
									dcInstance.setValue(
										tagName, value);
								}
							}
							Response response = runtimeDCS.save();
							if (response.isError())
							{
								System.err.println(response.getFirstErrorMessage());
							}
						}
					}
				}
			}
		}
		catch (Exception e)
		{
			System.err.println(e.getMessage());
		}
	}

	/**
	 * 获得自动采集的DCS
	 */
	private String getMachineDCS(Lot lot)
	{
		Step step = lot.getPresentRouteStep();
		if (step != null)
		{
			Vector dataCollections = step.getDataCollections();
			for (int i = 0; i < dataCollections.size(); i++)
			{
				DataCollectionSet dataCollectionSet = (DataCollectionSet) dataCollections.get(i);
				String category = dataCollectionSet.getCategory();
				if (IDCSCategory.EQUIPMENT.equals(category))
				{
					return dataCollectionSet.getName();
				}
			}
		}
		return null;
	}
	
	/**
	 * 班次用量消耗
	 * @param orderNumber	工单号
	 * @param shift			班次
	 * @param partNumber	物料代码
	 * @param bad_dust_qty	废粉量
	 * @param unusing_qty	损耗量
	 * @param consume_qty	消耗量
	 * @param wait_dust_qty	待用粉量
	 * @param consumeType	消耗类型
	 */
	public void saveOrderConsume(String orderNumber,String shift,String partNumber,BigDecimal bad_dust_qty,BigDecimal unusing_qty,BigDecimal consume_qty,BigDecimal wait_dust_qty,String consumeType) throws MESException
	{
		try
		{
			ATDefinition atDefinition = getFunctions().getATDefinition(
				AT_TABLE_PM_ORDER_CONSUME);
			Response response = atDefinition.createATRow();
			if (response.isError())
			{
				throw new Exception(getMessage("ERROR_114") + response.getFirstErrorMessage());
			}
			ATRow atRow = (ATRow) response.getResult();

			atRow.setValue(
				AT_COLUMN_PM_ORDER_CONSUME_ORDER_NUMBER, orderNumber);
			atRow.setValue(
				AT_COLUMN_PM_ORDER_CONSUME_SHIFT, shift);
			atRow.setValue(
				AT_COLUMN_PM_ORDER_CONSUME_CONSUME_TYPE, consumeType);
			atRow.setValue(
				AT_COLUMN_PM_ORDER_CONSUME_PART_NUMBER, partNumber);
			if (bad_dust_qty != null)
			{
				atRow.setValue(
					AT_COLUMN_PM_ORDER_CONSUME_BAD_DUST_QTY, bad_dust_qty);
			}
			if (unusing_qty != null)
			{
				atRow.setValue(
					AT_COLUMN_PM_ORDER_CONSUME_UNUSING_QTY, unusing_qty);
			}
			if (wait_dust_qty != null)
			{
				atRow.setValue(
					AT_COLUMN_PM_ORDER_CONSUME_WAIT_DUST_QTY, wait_dust_qty);
			}
			if (consume_qty != null)
			{
				atRow.setValue(
					AT_COLUMN_PM_ORDER_CONSUME_CONSUME_QTY, consume_qty);
			}

			response = atRow.save(
				getTrxTime(), null, null);
			if (response.isError())
			{
				throwException("ERROR_115");
			}

		}catch (Exception e) {
			throw new MESException(e, MODULE_PM, "保存班次用料信息");
		}
		
	}
	
	/**
	 * 打印采样条码
	 * @param atRow 取样检验单
	 */
	public void printSampleBarcode(ATRow atRow) throws MESException
	{
		Response response = getFunctions().getUserTransaction();
		if (response.isError())
		{
			throw new MESException(getMessage("ERROR_29"), MODULE_PM, "添加剂条码");
		}
		UserTransaction userTransaction = (UserTransaction) response.getResult();
		response = userTransaction.begin();
		if (response.isError())
		{
			throw new MESException(getMessage("ERROR_29"), MODULE_PM, "添加剂条码");
		}
		try
		{
			Order order = (Order) getFunctions().getProperty("sampleOrder");
			if(order == null)
			{
				throwException("ERROR_116");
			}
			String orderNumber = order.getOrderNumber();
			Lot lot = (Lot) getFunctions().getProperty("sampleLot");
			if(lot == null)
			{
				throwException("ERROR_117");
			}
			String lotName = lot.getName();
			if(atRow == null)
			{
				throwException("ERROR_118");
			}
			
			String barcode = "SAMPLE" + DateTimeUtils.formatDate(getTrxTime(), "yyyyMMddHHmmsssss");
			
			//更新采样信息表
			atRow.setValue("order_number", orderNumber);
			atRow.setValue("lot_name", lotName);
			atRow.setValue("serial_number", barcode);
			atRow.setValue("sample_time", getTrxTime());
			
			response = atRow.save(getTrxTime(), null, null);
			if(response.isError())
			{
				throwException("ERROR_119");
			}
			
			PrintComponent printComponent = new PrintComponent(getFunctions());
			
			printComponent.printBarCode(barcode, IPrintConstants.BARCODE_TYPE_MATERIAL);
			PrintComponent.logPrintRecord(getFunctions(), barcode,IPrintConstants.BARCODE_TYPE_SAMPLE,orderNumber,lot.getProductionLineName(),lot.getDescription());
			
			response = userTransaction.commit();
			if (response.isError())
			{
				throwException("ERROR_29");
			}
		}
		catch (Exception e)
		{
			userTransaction.rollback();
			throw new MESException(e, MODULE_PM, "添加剂条码");
		}
	}
	
	public static void main(String[] args) throws Exception
	{
//		System.out.println(DateTimeUtils.formatDate(new Date(), "yyyyMMddHHmmsssss"));
//		String xmlStr = "<WBSParam><Operator></Operator><RequestBill><WBSBillHead><WhsCD></WhsCD><REF3></REF3><REF2></REF2><REF1></REF1><BillNo></BillNo><Items><WBSBillItem><REF3></REF3><REF2></REF2><REF1></REF1><BatchNo></BatchNo><BillNo></BillNo><OutDate></OutDate><ItemID></ItemID><SupplierID></SupplierID><BillDate></BillDate><InDate></InDate><SupplierName></SupplierName><MaterialLable>TEST0902142504</MaterialLable><ItemName></ItemName><BillType></BillType><REF5></REF5><REF4></REF4><Qty></Qty></WBSBillItem></Items><SupplierID></SupplierID><BillDate></BillDate><BillType></BillType><REF5></REF5><REF4></REF4></WBSBillHead></RequestBill><Operate>MESmaterialReceiptConfirm</Operate></WBSParam>";
//		String result = MDUtils.invokeDNetWebService(
//			END_POINT, NAME_SPACE, METHOD_NAME_WBS, SOAP_ACTION_WBS, PARAMETER_NAME, xmlStr);
//		System.out.println(result);
//		XmlData xmlData = XMLUtils.strToXMLData(result);
//		Hashtable<String, ArrayList<Object>> data = xmlData.getData();
		//
//		String str = "dialogError(\"我靠\")\nprintln(\"aaaaaaa\")\ndialogError(\"我靠2\")\nprintln(\"bbbbb\")\ndialogError(\"我靠3\")\nprintln(\"bbbbb\")";
//		String str = "S 198.77 g";
//		str = str.substring(str.indexOf("S")+1, str.lastIndexOf("g")).trim();
//		System.out.println(str);
		System.out.println("1,2,3,4,5".replaceAll(",", "\n"));
	}
	
	/**
	 * 补印条码
	 * @param barcode		条码
	 * @param barcodeType	条码类型
	 */
	public void reprintBarcode(String barcode, Long barcodeType) throws MESException
	{
		try
		{
			PrintComponent printComponent = new PrintComponent(getFunctions());
			printComponent.printBarCode(barcode, barcodeType.intValue());
			PrintComponent.logRePrintRecord(getFunctions(), barcode);
		}
		catch (Exception e)
		{
			throw new MESException(e, MODULE_PM, "补印条码");
		}
		
	}
	
	/**
	 * 修正桶内物料数量
	 * @param carrier	桶
	 * @param lot		物料
	 * @param recalcQty	修正值
	 */
	public void recalcCarrier(Carrier carrier, Lot lot, BigDecimal recalcQty) throws Exception
	{
		Response response = getFunctions().getUserTransaction();
		if (response.isError())
		{
			throw new MESException(getMessage("ERROR_29"), MODULE_PM, "修正桶重量");
		}
		UserTransaction userTransaction = (UserTransaction) response.getResult();
		response = userTransaction.begin();
		if (response.isError())
		{
			throw new MESException(getMessage("ERROR_29"), MODULE_PM, "修正桶重量");
		}
		try
		{
			BigDecimal carrierQty = new BigDecimal(carrier.getUDA(UDA_CARRIER_QUANTITY));
			BigDecimal originalQty = lot.getPreciseQuantity();
			BigDecimal subQty = originalQty.subtract(recalcQty);	//扣减数量
			BigDecimal remainQty = carrierQty.subtract(subQty);	//桶剩余重量
			if(subQty.compareTo(BigDecimal.ZERO) < 0)
			{
				throw new Exception("修正值不允许大于当前物料的重量");
			}
			
			String materialName = lot.getName();
			
			response = carrier.removeLotQuantity(getTrxTime(), lot, subQty, null);
			if(response.isError())
			{
				throw new Exception("修正物料数量失败");
			}
			carrier.refresh();
			
			String orderName = carrier.getUDA(UDA_CARRIER_ORDER_NUMBER);
			ATRowFilter atRowFilter = getFunctions().createATRowFilter(AT_TABLE_PM_MATERIAL_SPLIT);
			atRowFilter.forColumnNameEqualTo(AT_COLUMN_PM_MATERIAL_SPLIT_ORDER_NUMBER,orderName);
//		    atRowFilter.forColumnNameEqualTo(AT_COLUMN_PM_MATERIAL_SPLIT_CONSUMED,true);
		    atRowFilter.forColumnNameEqualTo(AT_COLUMN_PM_MATERIAL_SPLIT_LOT_NAME, materialName);
		    atRowFilter.addOrderATColumnBy(AT_COLUMN_PM_MATERIAL_SPLIT_SCAN_TIME, IFilterSortOrders.DESCENDING);
		    atRowFilter.setMaxRows(1);
			Vector<ATRow> atRows = getFunctions().getFilteredATRows(atRowFilter, false);
			if(atRows != null && atRows.size() == 1)
			{
				ATRow atRow = atRows.firstElement();
				atRow.setValue(AT_COLUMN_PM_MATERIAL_SPLIT_CONSUMED, false);
				atRow.setValue(AT_COLUMN_PM_MATERIAL_SPLIT_QUANTITY, subQty);
				checkResponse(atRow.save(null, null, null));
				carrier.setUDA(remainQty.setScale(2,3).toString(),UDA_CARRIER_QUANTITY);
				checkResponse(carrier.save());
			}
			else
			{
				throw new Exception("无法找到需要修正的物料");
			}
			
			
			response = userTransaction.commit();
			if (response.isError())
			{
				throwException("ERROR_29");
			}
		}
		catch (Exception e)
		{
			userTransaction.rollback();
			throw new MESException(e, MODULE_PM, "修正桶重量");
		}
	}
	
	/**
	 * 修正桶重量
	 * @param carrier		桶
	 * @param qty			重量
	 */
	public void recalcCarrier(Carrier carrier,BigDecimal recalcQty) throws Exception
	{
		Response response = getFunctions().getUserTransaction();
		if (response.isError())
		{
			throw new MESException(getMessage("ERROR_29"), MODULE_PM, "修正桶重量");
		}
		UserTransaction userTransaction = (UserTransaction) response.getResult();
		response = userTransaction.begin();
		if (response.isError())
		{
			throw new MESException(getMessage("ERROR_29"), MODULE_PM, "修正桶重量");
		}
		try
		{
			//当前重量
			BigDecimal currentQty = new BigDecimal(carrier.getUDA(UDA_CARRIER_QUANTITY));
			if(recalcQty.compareTo(currentQty) >= 0)
			{
				throwException("修正值不允许大于或等于当前桶重量");
			}
			
			//扣减重量
			BigDecimal remainQty = currentQty.subtract(recalcQty);
			//获得最后一次扣减的物料名称
			String lastMaterialName = carrier.getUDA(UDA_CARRIER_LAST_MATERIAL);
			String orderName = carrier.getUDA(UDA_CARRIER_ORDER_NUMBER);
			ATRowFilter atRowFilter = getFunctions().createATRowFilter(AT_TABLE_PM_MATERIAL_SPLIT);
			atRowFilter.forColumnNameEqualTo(AT_COLUMN_PM_MATERIAL_SPLIT_ORDER_NUMBER,orderName);
		    atRowFilter.forColumnNameEqualTo(AT_COLUMN_PM_MATERIAL_SPLIT_CONSUMED,true);
		    atRowFilter.forColumnNameEqualTo(AT_COLUMN_PM_MATERIAL_SPLIT_LOT_NAME, lastMaterialName);
		    atRowFilter.addOrderATColumnBy(AT_COLUMN_PM_MATERIAL_SPLIT_SCAN_TIME, IFilterSortOrders.DESCENDING);
		    atRowFilter.setMaxRows(1);
			Vector<ATRow> atRows = getFunctions().getFilteredATRows(atRowFilter, false);
			if(atRows != null && atRows.size() == 1)
			{
				ATRow atRow = atRows.firstElement();
				atRow.setValue(AT_COLUMN_PM_MATERIAL_SPLIT_CONSUMED, false);
				atRow.setValue(AT_COLUMN_PM_MATERIAL_SPLIT_QUANTITY, remainQty);
				checkResponse(atRow.save(null, null, null));
				carrier.setUDA(recalcQty.setScale(2,3).toString(),UDA_CARRIER_QUANTITY);
				checkResponse(carrier.save());
			}
			else
			{
				throwException("无法找到桶内最后一次消耗的物料");
			}
			
			response = userTransaction.commit();
			if (response.isError())
			{
				throwException("ERROR_29");
			}
		}
		catch (Exception e)
		{
			userTransaction.rollback();
			throw new MESException(e, MODULE_PM, "修正桶重量");
		}
	}
	
	/**
	 * 格式化数字
	 * @param obj
	 * @throws Exception 
	 */
	public static String formatNumber(Object number,Integer scale) throws Exception
	{
		try
		{
			if(scale ==  null)
				scale = 2;
			BigDecimal bigDecimal = BigDecimal.ZERO;
			if(number != null)
			{
				bigDecimal = new BigDecimal(number.toString());
			}
			return bigDecimal.setScale(scale,BigDecimal.ROUND_UP).toString();
		}
		catch (Exception e) {
			throw new Exception(e);
		}
	}
	
	/**
	 * 创建一个异物登记
	 */
	public ForeignMatter createForeignMatter() throws MESException
	{
		try
		{
			ATDefinition atDefinition = getFunctions().getATDefinition(IATConstants.AT_TABLE_QM_FOREIGN_MATTER);
			Response response = atDefinition.createATRow();
			if(response.isError())
			{
				throwException("ERROR_120");
			}
			ATRow atRow = (ATRow) response.getResult();
			return new ForeignMatter(atRow);
		}
		catch (Exception e)
		{
			throw new MESException(e, MODULE_PM, "异物登记");
		}
	}
	
	public void sendAll() throws DatasweepException
	{
		Part part = getFunctions().getPart("9090093");
		try
		{
			sendPartToWMS(part, 0);
		}
		catch (MESException e)
		{
			e.printStackTrace();
		}
	}
	

	public void changeMessage()
	{
		try
		{
			Map<String, String> id_value_map = new HashMap<String, String>();
			Map<String, String> value_id_map = new HashMap<String, String>();
			
			String messageName = "OSIUIMessage";
			DsMessages dsMessage = getFunctions().getMessages(messageName);
			List messageIds=dsMessage.getMessageIDs();
			List locals=dsMessage.getLocales();
			Locale	ch=(Locale) locals.get(1);
			for(int i=0;i<messageIds.size();i++)
			{
				String messageId = (String) messageIds.get(i);
				String messageCh = dsMessage.getValue(messageId,ch);
				id_value_map.put(messageId, messageCh);
				value_id_map.put(messageCh, messageId);
			}
			
			FormFilter formFilter = new FormFilter(getFunctions().getCurrentUser().getServerImpl());
			formFilter.addSearchBy(IFormFilterAttributes.NAME, IFilterComparisonOperators.STARTSWITH, "osi");
			Vector forms = formFilter.exec();
			
			for (int k = 0; k < forms.size(); k++)
			{
				DeAnzaForm deanzaForm = (DeAnzaForm) forms.get(k);
				String formName = deanzaForm.getName();
				if (deanzaForm.isCheckedOut())
				{
					deanzaForm.checkIn(true);
				}
				deanzaForm.checkOut(true);
				Form form = (Form) Form.fromByteArray(deanzaForm.getForm());
				List<CControl> controls = form.getAllControls();
				for (int i = 0; i < controls.size(); i++)
				{
					Object obj = controls.get(i);
					if(!(obj instanceof CControl))
						continue;
					CControl control = controls.get(i);
					if (control instanceof FlatLabel || control instanceof FlatButton
						|| control instanceof GroupBox || control instanceof RadioButton || control instanceof CheckBox || control instanceof TabPage)
					{
						MessagesHolder messageHolder = control.getMessages();
						if (!messageName.equals(messageHolder.getMessagesName()))
						{
							messageHolder = new MessagesHolder();
							messageHolder.setMessagesName(messageName);
							control.setMessages(messageHolder);
						}
						MessageIdHolder messageidholder = control.getTextId();
						if (messageidholder == null
							|| !id_value_map.containsKey(messageidholder.getMessageId()))
						{
							String messageIdName = formName.toUpperCase() + "_" + i;
							dsMessage.setMessage(
								messageIdName, ch, control.getText());

							messageidholder = new MessageIdHolder();
							messageidholder.setMessagesName(messageName);
							messageidholder.setMessageId(messageIdName);

							control.setTextId(messageidholder);
						}

					}
					else if (control instanceof DsGrid)
					{
						MessagesHolder messageHolder = control.getMessages();
						if (!messageName.equals(messageHolder.getMessagesName()))
						{
							messageHolder = new MessagesHolder();
							messageHolder.setMessagesName(messageName);
							control.setMessages(messageHolder);
						}

						String dsGridName = control.getName();
						ColumnDefinition[] columnDefinitions = ((DsGrid) control)
							.getColumnDefinitions();
						for (int j = 0; j < columnDefinitions.length; j++)
						{
							MessageIdHolder messageidholder = columnDefinitions[j].getHeadingId();
							if (messageidholder == null
								|| !id_value_map.containsKey(messageidholder.getMessageId()))
							{
								String messageIdName = formName.toUpperCase() + "_"
									+ dsGridName.toUpperCase() + "_" + j;
								dsMessage.setMessage(
									messageIdName, ch, columnDefinitions[j].getHeading());

								messageidholder = new MessageIdHolder();
								messageidholder.setMessagesName(messageName);
								messageidholder.setMessageId(messageIdName);

								columnDefinitions[j].setHeadingId(messageidholder);
							}
						}
						((DsGrid) control).setColumnDefinitions(columnDefinitions);

					}
				}
				deanzaForm.setForm(form.toByteArray());
				deanzaForm.save(
					null, null);
				deanzaForm.checkIn(true);
				Response response = dsMessage.save(
					null, null);
				if (response.isError())
				{
					System.out.println(response.getFirstErrorMessage());
				}
			}
		}
		catch (Exception e)
		{
			e.printStackTrace();
		}
	}
	
	public void changeScriptMessage()
	{
		try
		{
			Map<String, String> id_value_map = new HashMap<String, String>();
			Map<String, String> value_id_map = new HashMap<String, String>();
			
//			String messageName = "OSIPMMessage";
//			String messageName = "OSIBaseMessage";
//			String messageName = "OSIEMMessage";
			String messageName = "OSIQMMessage";
			DsMessages dsMessage = getFunctions().getMessages(messageName);
			List messageIds=dsMessage.getMessageIDs();
			List locals=dsMessage.getLocales();
			Locale	ch=(Locale) locals.get(1);
			for(int i=0;i<messageIds.size();i++)
			{
				String messageId = "getMessage(\""+messageName+"\",\""+(String) messageIds.get(i)+"\")";
				String messageCh = dsMessage.getValue(messageId,ch);
				id_value_map.put(messageId, messageCh);
				value_id_map.put(messageCh, messageId);
			}
			
			FormFilter formFilter = new FormFilter(getFunctions().getCurrentUser().getServerImpl());
			formFilter.addSearchBy(IFormFilterAttributes.NAME, IFilterComparisonOperators.STARTSWITH, "osi_base_QM");
//			formFilter.addSearchBy(IFormFilterAttributes.NAME, IFilterComparisonOperators.STARTSWITH, "osi_dlg_QM");
			Vector forms = formFilter.exec();
			
			String dialogOkRegex = "dialogOk\\(\\\".*?\\\",\\\".*?\\\"\\)";
			String dialogErrorRegex = "dialogError\\(\"(.*?)\"\\)";
			
			Pattern patternOk = Pattern.compile(dialogOkRegex);
			Pattern patternError = Pattern.compile(dialogErrorRegex);
			
			
			for (int k = 0; k < forms.size(); k++)
			{
				DeAnzaForm deanzaForm = (DeAnzaForm) forms.get(k);
				String formName = deanzaForm.getName();
				if (deanzaForm.isCheckedOut())
				{
					deanzaForm.checkIn(true);
				}
				deanzaForm.checkOut(true);
				Form form = (Form) Form.fromByteArray(deanzaForm.getForm());
				List<CComponent> controls = form.getAllControls();
				int numOk = 0;		//dialogOk后缀
				int numError = 0;	//dialogError后缀
				for (int i = 0; i < controls.size(); i++)
				{
					CComponent obj = controls.get(i);
					String componentName = obj.getName();
					String[] events = obj.getEvents();
					for (int j = 0; j < events.length; j++)
					{
						String event = events[j];
						String script = obj.retrieve(event);
						if(StringUtils.isNull(script) || script.contains("getMessage"))
						{
							continue;
						}
						script = script+" ";
						String newScript = new String(script);
						if(StringUtils.isNotNull(script))
						{
							//确定dialogOk数量
							Matcher matcherOk = patternOk.matcher(script);
							while(matcherOk.find())
							{
								String dialogOkString = matcherOk.group();
								String title = dialogOkString.substring(
									dialogOkString.indexOf("(\"") + 2,
									dialogOkString.indexOf("\",\""));
								String context = dialogOkString.substring(
									dialogOkString.indexOf("\",\"") + 3,
									dialogOkString.indexOf("\")"));

								if (id_value_map.containsKey(title))
								{
									continue;
								}

								// 判断是否已经加过message
								System.out.println("正在修改form:" + formName + "\t控件:" + componentName
									+ "\t dialogOk" + "\t标题为：" + title);
								System.out.println("正在修改form:" + formName + "\t控件:" + componentName
									+ "\t dialogOk" + "\t内容为：" + context);

								String messageIdTitleName = formName.toUpperCase()
									+ "_DLGOK_TITLE_" + numOk;
								String messageIdContextName = formName.toUpperCase() + "_DLGOK_"
									+ numOk;
								String titleMsgId = "getMessage(\""+messageName+"\",\""
									+ messageIdTitleName + "\")";
								String contextMsgId = "getMessage(\""+messageName+"\",\""
									+ messageIdContextName + "\")";

								id_value_map.put(
									titleMsgId, title);
								id_value_map.put(
									contextMsgId, messageIdContextName);

								dsMessage.setMessage(
									messageIdTitleName, ch, title);
								dsMessage.setMessage(
									messageIdContextName, ch, context);

								newScript = newScript.replace(
									"\""+title+"\"", titleMsgId);
								newScript = newScript.replace(
									"\""+context+"\"", contextMsgId);
								numOk++;
							}
							
							//确定dialogError数量
							Matcher matcherError = patternError.matcher(script);
							while(matcherError.find())
							{
								String dialogErrorString = matcherError.group();
								String context = dialogErrorString.substring(dialogErrorString.indexOf("(\"")+2, dialogErrorString.indexOf("\")"));
								
								if(id_value_map.containsKey(context))
								{
									continue;
								}
								
								System.out.println("正在修改form:"+formName+"\t控件:"+componentName +"\t dialogError"+ "\t内容为："+context);
								
								String messageIdContextName = formName.toUpperCase() + "_DLGERROR_" + numError;
								String contextMsgId = "getMessage(\""+messageName+"\",\""+messageIdContextName+"\")";
								
								id_value_map.put(contextMsgId, messageIdContextName);
								
								dsMessage.setMessage(
									messageIdContextName, ch, context);
								
								newScript = newScript.replace("\""+context+"\"", contextMsgId);
								numError++;
							}
						}
						obj.put(event, newScript);
					}
				}
				deanzaForm.setForm(form.toByteArray());
				deanzaForm.save(
					null, null);
				deanzaForm.checkIn(true);
				Response response = dsMessage.save(
					null, null);
				if (response.isError())
				{
					System.out.println(response.getFirstErrorMessage());
				}
			}
		}
		catch (Exception e)
		{
			e.printStackTrace();
		}
	}
	
	public void changeSubroutine()
	{

		try
		{
			Map<String, String> id_value_map = new HashMap<String, String>();
			Map<String, String> value_id_map = new HashMap<String, String>();

			// String messageName = "OSIPMMessage";
			// String messageName = "OSIBaseMessage";
			// String messageName = "OSIEMMessage";
			String messageName = "OSIQMMessage";
			DsMessages dsMessage = getFunctions().getMessages(
				messageName);
			List messageIds = dsMessage.getMessageIDs();
			List locals = dsMessage.getLocales();
			Locale ch = (Locale) locals.get(1);
			for (int i = 0; i < messageIds.size(); i++)
			{
				String messageId = "getMessage(\"" + messageName + "\",\""
					+ (String) messageIds.get(i) + "\")";
				String messageCh = dsMessage.getValue(
					messageId, ch);
				id_value_map.put(
					messageId, messageCh);
				value_id_map.put(
					messageCh, messageId);
			}

			// FormFilter formFilter = new
			// FormFilter(getFunctions().getCurrentUser().getServerImpl());
			Vector subroutines = new Vector();
			subroutines.add(getFunctions().getSubroutine("osi_qm_chemicalProdChk"));
			subroutines.add(getFunctions().getSubroutine("osi_qm_chkTb"));
			subroutines.add(getFunctions().getSubroutine("osi_qm_comingMatChk"));
			subroutines.add(getFunctions().getSubroutine("osi_qm_common"));
			subroutines.add(getFunctions().getSubroutine("osi_qm_deviation"));
			subroutines.add(getFunctions().getSubroutine("osi_qm_equAd"));
			subroutines.add(getFunctions().getSubroutine("osi_qm_inoutSourceChk"));
			subroutines.add(getFunctions().getSubroutine("osi_qm_shipReport"));

			String dialogOkRegex = "dialogOk\\(\\\".*?\\\",\\\".*?\\\"\\)";
			String dialogErrorRegex = "dialogError\\(\"(.*?)\"\\)";

			Pattern patternOk = Pattern.compile(dialogOkRegex);
			Pattern patternError = Pattern.compile(dialogErrorRegex);

			for (int k = 0; k < subroutines.size(); k++)
			{
				Subroutine subroutine = (Subroutine) subroutines.get(k);
				String subroutineName = subroutine.getName();
				if (subroutine.isCheckedOut())
				{
					subroutine.checkIn(true);
				}
				subroutine.checkOut(true);
				String script = subroutine.getSubroutine();
				int numOk = 0; // dialogOk后缀
				int numError = 0; // dialogError后缀
				if (StringUtils.isNull(script) || script.contains("dialogError(getMessage") || script.contains("dialogOk(getMessage"))
				{
					continue;
				}
				script = script + " ";
				String newScript = new String(script);
				if (StringUtils.isNotNull(script))
				{
					// 确定dialogOk数量
					Matcher matcherOk = patternOk.matcher(script);
					while (matcherOk.find())
					{
						String dialogOkString = matcherOk.group();
						String title = dialogOkString.substring(
							dialogOkString.indexOf("(\"") + 2, dialogOkString.indexOf("\",\""));
						String context = dialogOkString.substring(
							dialogOkString.indexOf("\",\"") + 3, dialogOkString.indexOf("\")"));

						if (id_value_map.containsKey(title))
						{
							continue;
						}

						// 判断是否已经加过message
						System.out.println("正在修改subroutine:" + subroutineName + "\t dialogOk" + "\t标题为：" + title);
						System.out.println("正在修改subroutine:" + subroutineName + "\t dialogOk" + "\t内容为：" + context);

						String messageIdTitleName = subroutineName.toUpperCase() + "_DLGOK_TITLE_"
							+ numOk;
						String messageIdContextName = subroutineName.toUpperCase() + "_DLGOK_" + numOk;
						String titleMsgId = "getMessage(\"" + messageName + "\",\""
							+ messageIdTitleName + "\")";
						String contextMsgId = "getMessage(\"" + messageName + "\",\""
							+ messageIdContextName + "\")";

						id_value_map.put(
							titleMsgId, title);
						id_value_map.put(
							contextMsgId, messageIdContextName);

						dsMessage.setMessage(
							messageIdTitleName, ch, title);
						dsMessage.setMessage(
							messageIdContextName, ch, context);

						newScript = newScript.replace(
							"\"" + title + "\"", titleMsgId);
						newScript = newScript.replace(
							"\"" + context + "\"", contextMsgId);
						numOk++;
					}

					// 确定dialogError数量
					Matcher matcherError = patternError.matcher(script);
					while (matcherError.find())
					{
						String dialogErrorString = matcherError.group();
						String context = dialogErrorString.substring(
							dialogErrorString.indexOf("(\"") + 2, dialogErrorString.indexOf("\")"));

						if (id_value_map.containsKey(context))
						{
							continue;
						}

						System.out.println("正在修改subroutine:" + subroutineName	+ "\t dialogError" + "\t内容为：" + context);

						String messageIdContextName = subroutineName.toUpperCase() + "_DLGERROR_"
							+ numError;
						String contextMsgId = "getMessage(\"" + messageName + "\",\""
							+ messageIdContextName + "\")";

						id_value_map.put(
							contextMsgId, messageIdContextName);

						dsMessage.setMessage(
							messageIdContextName, ch, context);

						newScript = newScript.replace(
							"\"" + context + "\"", contextMsgId);
						numError++;
					}
				}
				subroutine.setSubroutine(newScript);
				subroutine.save(
					null, null);
				subroutine.checkIn(true);
				Response response = dsMessage.save(
					null, null);
				if (response.isError())
				{
					System.out.println(response.getFirstErrorMessage());
				}
			}
		}
		catch (Exception e)
		{
			e.printStackTrace();
		}
	
	}
}
